Friday 2 December 2011

Big numbers

Rebol can works with integers number to 9 digits, this means that you can write:

>> -999999999
== -999999999
>> 999999999
== 999999999

If you digit a bigger number is automatically transformed in a decimal precision number. Decimal numbers has 15 digits of precision:

>> 12345678901234567890123456789
== 1.23456789012346E+28


This behavior is normal, it's difficult to preform calculus that need more than 15 digits. For example in engineering field no more than 3-4 digits is necessary.
However it can be useful working with big integers, like indexing of pages, databases, etc.
Rebol can manipulate any longer integer, if you need it; just transform the number in a string and use the following script:

rebol [
Author: [ "Alban Gabillon"   "Massimiliano Vessi" ]
  Library: [
        level: 'intermediate
        platform: 'all
        type: tool
        domain: [math]
        tested-under: windows
        support: none
        license: none
        see-also: none
        ]
    History: [
        [1.0 22-mar-2007 "First version"]
        [2.1 29-11-2011 "Now it's more human usable"]
        ]
    Title:       "Bignumbers.r"
    File:   %bignumbers.r
    Owner:       "Alban Gabillon"
    Version:         2.1.0
    Date:       22-Mar-2007
    Purpose: {
    This script allows you to apply the four classical operations (big-add, big-subtract, big-divide, big-multiply) on very big positive integers.
    Size of the integers is only limited by the size of a rebol string since numbers are represented as strings.   }]
big-add: func [
    {add two big numbers }
    n1 [string!]
    n2 [string!]
    /local mem plus n result][
    n1: reverse copy n1
    n2: reverse copy n2
    mem: 0
    result: copy ""
    if (length? n1) < (length? n2) [n: n1 n1: n2 n2: n]
    while [not tail? n2][
        plus: to-string ((to-integer to-string n1/1) + (to-integer to-string n2/1) + mem)
        either (length? plus) = 1 [mem: 0 result: insert result plus/1][mem: 1 result: insert result plus/2]
        n1: next n1
        n2: next n2
        ]
    while [  not tail? n1][
        plus: to-string ((to-integer to-string n1/1) + mem)
        either (length? plus) = 1 [mem: 0 result: insert result plus/1][mem: 1 result: insert result plus/2]
        n1: next n1
        ]
    either mem = 1 [insert result #"1"][insert result copy n1]
    result: head result
    return  result
    ]
big-multiply: func   ["multiply two big numbers" n1 [string!] n2 [string!] /local temp ] [
    n1: reverse   copy n1
    n2: copy n2
    temp:   copy "0"
    foreach item n1 [      
        for i 1 (to-integer to-string item) 1 [                    
            temp: big-add   temp   n2        
            ]  
        append n2 "0"      
        ]  
    return temp
    ]
big-greater: func [
    {compare two bignumbers:
    return true if n1 > n2
    return false if n1 < n2
    return none if n1 = n2
    }

    n1 [string!]
    n2 [string!]][
    n1: reverse copy n1
    n2: reverse copy n2
    either (length? n1) <> (length? n2) [(length? n1) > (length? n2)][
        either equal? n1 n2 [none][
            n1: back tail n1
            n2: back tail n2
            while [n1/1 = n2/1][n1: back n1 n2: back n2]
            n1/1 > n2/1
            ]
        ]
    ]
big-sub: func [
    {substract the smallest big number from the largest one }
    n1 [string!]
    n2 [string!]
    /local mem minus n result][
    if big-greater n2 n1 [n: n1 n1: n2 n2: n]
    n1: reverse copy n1
    n2: reverse copy n2
    mem: 0
    result: copy ""
    while [not tail? n2][
        minus: to-string (((to-integer to-string n1/1) - mem) + (10 - (to-integer to-string n2/1)))
        either (length? minus) = 1 [mem: 1 result: insert result minus/1][mem: 0 result: insert result minus/2]
        n1: next n1
        n2: next n2
        ]
    while [all[mem = 1 not tail? n1]][
        minus: to-string ((to-integer to-string n1/1) + (10 - mem))
        either (length? minus) = 1 [mem: 1 result: insert result minus/1][mem: 0 result: insert result minus/2]
        n1: next n1
        ]
    insert result copy n1
    result: back tail result
    while [all [result/1 = #"0" not head? result]][result: back result]
    clear next result
    result: head result
    return reverse result
    ]
big-divide: func [
    {divide two big numbers   -
    output is a block of two numbers [quotient remainder]}

    n1 [string!]
    n2 [string!]
    /local   count   ][
        n1: copy n1 ;this avoid to modify the original block
        if big-greater n2 n1 [return reduce ["0" n1]] ;obvius
        if equal? n1 n2 [return reduce ["1" "0"]] ;obvius  
        count: "0"
        while [big-greater n1 n2 ] [
            n1: big-sub n1 n2
            count: big-add count "1"
            ]
        if equal? n1 n2 [
            count: big-add count "1"
            n1: "0"
            ]
        return   reduce [count n1]
        ]



It can be used this way (now I'll use small number as example):

>> big-add "253" "2"
== "255"
>> big-sub "253" "2"
== "251"
>> big-multiply "253" "2"
== "506"
>> big-divide "253" "2"
== ["126" "1"]


Real world examples:

>> big-add "123456789012345678901234567890" "123456789012345678901234567890"
== "246913578024691357802469135780"
>> big-sub "123456789012345678901234567890" "123456789012345678901234567890"
== "0"
>> big-multiply "123456789012345678901234567890" "123456789012345678901234567890"
== {15241578753238836750495351562536198787501905199875019052100}
>> big-divide "123456789012345678901234567890" "123456789012345678901234567890"
== ["1" "0"]

No comments:

Post a Comment