how to do math in vim script

619 views
Skip to first unread message

Ralf Schmitt

unread,
Sep 26, 2007, 5:24:42 PM9/26/07
to vim_use

Hi List,

I wanted to do some math in vim script to calculate for
example 80% of the rows vim uses in current window. So
I started to play with the devision operator and the
variables. It seems to me vim script just got integers?

echo 100 / 20 -> 5
echo 20 / 100 -> 0
echo 20.0 / 100.0 -> 2000

oh my, any help?


kind regards
Ralf

Tim Chase

unread,
Sep 26, 2007, 5:48:24 PM9/26/07
to vim...@googlegroups.com
Ralf Schmitt wrote:
> It seems to me vim script just got integers?

yep. There's not much need for floating point when doing
text-editing. It doesn't have built in support for trigonometric
functions, complex numbers or matrix math either.

If you just want percentages, you can do integer math on scaled
up numbers. Just remember to carry your scaling into
multipliers/divisors

> echo 100 / 20 -> 5
> echo 20 / 100 -> 0
> echo 20.0 / 100.0 -> 2000
>
> oh my, any help?

It's a horrible experience. I wrote a proof-of-concept
"AddDecimal" function which more or less did it via the
old-school method of "math by hand, lining up decimal points".
Lather/Rinse/Repeat for other operators in order to get
SubtractDecimal, MultiplyDecimal, and DivideDecimal. When
dividing, beware of repeating decimals.

It was sent to the ML in a thread entitled "Arithmetic", but I
can't for the life of me get Google to regurgitate a link to it.

Fortunately, I kept that post around as it was a nifty bit of
fun, so I've included it below.

Your best bet is to used a linked-in language (Vim can be built
with embedded access to Python, Perl, and Ruby...perhaps others?)
which are better suited for floating-point math.

-tim


function! AddDecimal(one, two)
if (match(a:one, '\.') < 0) && (match(a:two, '\.') < 0)
return a:one+a:two;
endif
if (match(a:one, '\.') < 0)
let l:onewhole = a:one
let l:onefrac = ''
else
let l:onewhole = substitute(a:one, '\..*', '', '')
let l:onefrac = substitute(a:one, '.*\.', '', '')
endif
if (match(a:two, '\.') < 0)
let l:twowhole = a:two
let l:twofrac = ''
else
let l:twowhole = substitute(a:two, '\..*', '', '')
let l:twofrac = substitute(a:two, '.*\.', '', '')
endif
let l:onefraclen = strlen(l:onefrac)
let l:twofraclen = strlen(l:twofrac)
if strlen(l:onefrac) > strlen(l:twofrac)
" use the length of onefrac
let l:decimalPlaces = strlen(l:onefrac)
else " use the length of twofrac
let l:decimalPlaces = strlen(l:twofrac)
endif
let l:counter = 0
let l:zeros = ''
while (l:counter < l:decimalPlaces)
let l:counter = l:counter + 1
let l:zeros = l:zeros.'0'
endw
let l:newone = l:onewhole.strpart(l:onefrac.l:zeros, 0,
l:decimalPlaces)
let l:newtwo = l:twowhole.strpart(l:twofrac.l:zeros, 0,
l:decimalPlaces)

" strip off leading zeroes which caused it to think the # was
octal
let l:newone = substitute(l:newone, '^\(-\=\)0*', '\1','')
let l:newtwo = substitute(l:newtwo, '^\(-\=\)0*', '\1', '')

" actually do the addition
let l:sum = l:newone+l:newtwo

" fix up to make sure things get realigned...this might be wrong
let l:sum = substitute(l:sum, '\(-\=\)\(.*\)',
'\1'.l:zeros.'\2', '')

" insert the decimal point back in visually
let l:sum = substitute(l:sum, '\(.\{'.l:decimalPlaces.'}\)$',
'.\1', '')

" strip out any leading or trailing zeros
let l:sum = substitute(l:sum, '^\(-\=\)0*\(.*\)0*$', '\1\2', '')

" clean it back up, putting a zero before the decimal pt if
no whole bit
let l:sum = substitute(l:sum, '^\(-\=\)\.', '\10.', '')
return l:sum
endfunction

function! TestPair(x, y)
echo substitute(' '.a:x, '.*\(.\{10}\)$', '\1', '')
echo substitute(' +'.a:y, '.*\(.\{10}\)$', '\1', '')
echo "=========="
echo substitute(' '.AddDecimal(a:x,a:y),
'.*\(.\{10}\)$', '\1', '')
echo "\n"
endfunction

function! TestAdding()
call TestPair('0.001', '0.02')
call TestPair('3.14', '0.08')
call TestPair('-4', '3.14')
call TestPair('-4.0', '3.141')
call TestPair('9.0001', '1.002')
call TestPair('1.0001', '-1.002')
call TestPair('0.0001', '-0.002')
endfunction


A.Politz

unread,
Sep 26, 2007, 5:57:10 PM9/26/07
to vim...@googlegroups.com
Ralf Schmitt wrote:

Use any of the language interfaces, perl, ruby you name it.

:perl VIM::Msg(20.0/100) -> 0.2

Make yourself familiar with your systems preferred calculator.

echo system('echo "scale=1;20.0/100.0"|bc') -> .2

Do you really need to know, that 80% of vims currently used
rows in a window equals 30.6152 ,or isn't 30 good enough ?

-ap


--
Ich hab geträumt, der Krieg wär vorbei.

Suresh Govindachar

unread,
Sep 26, 2007, 5:54:08 PM9/26/07
to v...@vim.org, Ralf Schmitt

Ralf asked:

To evaluate an equation (e.g., 2 + cos(3.1412)) I yank the
equation into the * register and hit \e; and the answer
(1.00000007708842) is echoed and also appears below the line the
cursor was on! This magic happens because I have mapped \e to the
thing that does the evaluation and echos the answer and pastes the
answer into the line below the cursor. The thing uses perl and
is:

" evaluate numerical expression in unnammed buffer
" and echo and append result
nmap \e :perl my $foo = eval(VIM::Eval('@*'));
\ VIM::DoCommand("let @* = '" . $foo . " '" );
\ my @pos = $curwin->Cursor();
\ $curbuf->Append($pos[0], $foo);
\ VIM::Msg($foo);<CR>

--Suresh


Kev

unread,
Sep 26, 2007, 6:49:34 PM9/26/07
to vim...@googlegroups.com
I used to use the Perl option to do this, but use mainly Ruby for
programming so I tried the following:
1) visually highlight the expression: 7*2-3.2 or whatever.
2) yank it to a register "ya
3) :ruby print <c-r>a and then press enter

Kevin

> Ralf asked:
> >
> > I wanted to do some math in vim script to calculate for example
> > 80% of the rows vim uses in current window. So I started to play
> > with the devision operator and the variables. It seems to me vim
> > script just got integers?
> >
> > echo 100 / 20 -> 5
> > echo 20 / 100 -> 0
> > echo 20.0 / 100.0 -> 2000
> >
>

Bill McCarthy

unread,
Sep 26, 2007, 11:02:49 PM9/26/07
to Ralf Schmitt, Vim List
On Wed 26-Sep-07 4:24pm -0600, Ralf Schmitt wrote:

> I wanted to do some math in vim script to calculate for
> example 80% of the rows vim uses in current window. So
> I started to play with the devision operator and the
> variables. It seems to me vim script just got integers?

For integer percentages with rounding, i.e. calculate p% of n:

echo (n*p+50)/100

For more complex math, check out using BC with:

http://vim.sourceforge.net/tips/tip.php?tip_id=1349

--
Best regards,
Bill

Bill McCarthy

unread,
Sep 26, 2007, 11:02:49 PM9/26/07
to Ralf Schmitt, Vim List
On Wed 26-Sep-07 4:24pm -0600, Ralf Schmitt wrote:

> I wanted to do some math in vim script to calculate for
> example 80% of the rows vim uses in current window. So
> I started to play with the devision operator and the
> variables. It seems to me vim script just got integers?

For integer percentages with rounding, i.e. calculate p% of n:

John Beckett

unread,
Sep 26, 2007, 11:50:41 PM9/26/07
to vim...@googlegroups.com
Bill McCarthy wrote:
> For more complex math, check out using BC with:
> http://vim.sourceforge.net/tips/tip.php?tip_id=1349

Hi Bill, I see you made valuable comments in that tip, and I can see why you
linked to the old tip site (because the import has destroyed the formatting
in this tip on the new site).

Any chance you could get inspired to fix the imported tip at

http://vim.wikia.com/wiki/VimTip1349

Preferably, you would create an account and logon, but that's optional. Then
you would click Edit and, well, you would edit. Since the imported tip is a
bit of a mess, you might copy the text out of the browser edit box into Vim,
and work there.

Here's what's needed:

* Delete the stupid blank lines that somehow were inserted during the
import. Ideally, you would join the lines in a paragraph (on the wiki, a
paragraph is a single line that wraps; use one blank line between paras).

* Insert a new line before and after each block of code, like this:

<pre>
" Here is some stuff that you want in a fixed-width font.
" It will appear exactly as typed.
</pre>

* Fix the code indents (most of these were screwed up by the import).
Sometimes I just copy the text from the old tip. I find that two-space
indents work pretty well on the wiki (although I would use four in my code).

* Optional: Replace ":help :s\=" with "{{help|id=:s\=}}" (click the "General
guidelines" in the Review box at the top of the tip to lead to docs on
Template:Help).

* This tip uses a bar ('|') and unfortunately the import does something
tricky which breaks when a bar is used. The solution is to find the "}}"
just before "== Comments ==". Delete the "}}" line. At the top of the tip,
insert the "}}" line followed by a blank line, just after the line "|text=".
You would end up with:

---begin---
|text=
}}

This tip is to add a good calculator....
---end---

In the "Summary" box, write something like "Fixed formatting".

Click the "Show Preview" button to see if it worked, then "Save".

Yes, I could have fixed the tip myself ... but we really need some help on
the wiki folks! Please try it.

John

thomas

unread,
Sep 27, 2007, 12:29:41 AM9/27/07
to vim_use
> echo 100 / 20 -> 5
> echo 20 / 100 -> 0
> echo 20.0 / 100.0 -> 2000

In order to calculate 80% of the lines, instead of

&lines * 0.8

do:

&lines * 80 / 100

You can multiply numbers with some factor to move the decimal place to
the right. For fancier stuff, you'll have to "resort" to builtin-perl/
python/ruby etc. if available.

Charles E Campbell Jr

unread,
Sep 27, 2007, 9:26:28 AM9/27/07
to vim...@googlegroups.com
thomas wrote:

Essentially that's what I do for Mines.vim ; it uses integer arithmetic
to report the success rate to the third decimal place.
I also use my own program, calc, to do floating point calculations when
I need them, along with some maps to make that easier.

Regards,
Chip Campbell

Yongwei Wu

unread,
Sep 27, 2007, 10:26:16 AM9/27/07
to vim...@googlegroups.com
On 27/09/2007, Charles E Campbell Jr <drc...@campbellfamily.biz> wrote:
> I also use my own program, calc, to do floating point calculations when
> I need them, along with some maps to make that easier.

Same as I do. If anybody wants to have look at the possible mappings,
check http://wyw.dcweb.cn/vim/_vimrc.html and search for "arithmetic".

I use my own calcu program on Windows (Microsoft has used the name
"calc" already). On Linux I use this simple script:

#! /bin/sh
echo "$*" | sed -e $'s/\r$//' -e 's/sin *(/s(/g' -e 's/cos *(/c(/g' -e
's/atan *(/a(/g' -e 's/log *(/l(/g' -e 's/exp *(/e(/g' | bc -l

Best regards,

Yongwei

--
Wu Yongwei
URL: http://wyw.dcweb.cn/

Richard Hartmann

unread,
Sep 28, 2007, 6:21:02 AM9/28/07
to vim...@googlegroups.com
On 27/09/2007, Charles E Campbell Jr <drc...@campbellfamily.biz> wrote:

> Essentially that's what I do for Mines.vim

Now that is a fun thing. Are there any other games for vim?


Richard

Tony Mechelynck

unread,
Sep 28, 2007, 6:34:30 AM9/28/07
to vim...@googlegroups.com

There are a few that are distributed with Vim. Check the subfolders of
$VIMRUNTIME/macros/.


Best regards,
Tony.
--
Today is the tomorrow you worried about yesterday

Richard Hartmann

unread,
Sep 28, 2007, 7:21:49 AM9/28/07
to vim...@googlegroups.com
On 28/09/2007, Tony Mechelynck <antoine.m...@gmail.com> wrote:

> There are a few that are distributed with Vim. Check the subfolders of
> $VIMRUNTIME/macros/.

Thanks.


Richard

Hari Krishna Dara

unread,
Sep 28, 2007, 11:01:08 AM9/28/07
to vim...@googlegroups.com

There are much better games on vim.org scripts section. There is even a
subsection called games for you to search.

http://www.vim.org/scripts/script_search_results.php?keywords=&script_type=game&order_by=rating&direction=descending&search=search

There is a lot of noise, but the first few are the good ones.

--
Hari

>
> Thanks.
>
>
> Richard
>
> >
>

Reply all
Reply to author
Forward
0 new messages