Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
doubling a number
#1
i have a giant number in a str. i want to double it and get a str result, keeping all of the precision. int(number)*2 can't do this because the number may not be whole. float(number)*2 can't do this because the precision needed may exceed what float supports. what can do this?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#2
For integers, Python int type suffices
>>> number = "23278327809283209832832093822093820938029830398320938209"
>>> str(2 * int(number))
'46556655618566419665664187644187641876059660796641876418'
Using gmpy2's mpz type
>>> number = "23278327809283209832832093822093820938029830398320938209"
>>> from gmpy2 import mpz
>>> double = 2 * mpz(number)
>>> double
mpz(46556655618566419665664187644187641876059660796641876418)
>>> str(double)
'46556655618566419665664187644187641876059660796641876418'
>>> 
Also for real numbers
>>> number = "23278327809283209832832093822093820938029830398320938209.23232332323232323"
>>> import gmpy2
>>> gmpy2.get_context().precision = 500
>>> from gmpy2 import mpfr
>>> double = 2 * mpfr(number)
>>> str(double)
'46556655618566419665664187644187641876059660796641876418.464646646464646460000000000000000000000000000000000000000000000000000000000000000000000000000001'
Reply
#3
Maybe some simple doubling function?

def double(text):
    doubled = []
    carry = 0
    for num in text[::-1]:
        if num in ('.', ','):
            doubled.append(num)
        else:
            quotient, reminder = divmod(2 * int(num), 10)
            doubled.append(str(reminder+carry))
            carry = quotient
    if carry:
        doubled.append(str(carry))

    return ''.join(doubled[::-1])


for num in ("1", "10", "12.5", "1.9", "99", "99.7899", "99.999"):
    print(f"{num}, {double(num)}")

1, 2
10, 20
12.5, 25.0
1.9, 3.8
99, 198
99.7899, 199.5798
99.999, 199.998
Gribouillis likes this post
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#4
A faster version using Python's arbitrarily sized integers
def double(text):
    parts = text.split('.', 1)
    a, b = parts if len(parts) == 2 else (parts[0], '')
    shift = len(b)
    n = str(int(a + b) * 2)
    if shift:
        return f'{n[:-shift]}.{n[-shift:]}'
    else:
        return n

for num in ("1", "10", "12.5", "1.9", "99", "99.7899", "99.999"):
    print(f"{num}, {double(num)}")
This code assumes that the initial string doesn't have an exponential part such as 31.4e-1
Reply
#5
so there is nothing to do this already defined in some module; i must pass along this or some definition to do it? i don't think there will be exponentials but i am not 100% sure. my earliest worry when thinking about doing my own function was complex numbers. these will be typically more than 100 digits, possibly over 2000, but always in decimal. so, this function will have to check types or try/except everything.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#6
(Jul-16-2023, 11:25 PM)Skaperen Wrote: so there is nothing to do this already defined in some module
But there is, I thought you knew. It is decimal for computations with arbitrary precision.

import decimal

number = "23278327809283209832832093822093820938029830398320938209.23232332323232323"

decimal.getcontext().prec = len(number)  # Set the precision. (Perhaps decimal point should not be counted.)
print(number)
print(decimal.Decimal(number) * decimal.Decimal(2))
Output:
23278327809283209832832093822093820938029830398320938209.23232332323232323 46556655618566419665664187644187641876059660796641876418.46464664646464646
Gribouillis and Skaperen like this post
Reply
#7
is there any limit to precision setting for decimal? will a few million digits work on a 4 GB system? how can the precision be restored to what it originally was (in a function to do the doubling)?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#8
There is indeed a limit to the number of digits, defined by decimal.MAX_PREC, which is 999.999.999.999.999.999 on 64-bit platforms. So on a system with 4 GB RAM the number of digits will be limited by the available RAM. But this will be the same with every other method you choose. This is not entirely true because we do not know how many times the data is copied internally (from string to decimal input -> to decimal output and back to string may need 4 times the number of bytes of the input string). But I guess the number of digits will not be more than some Millions and you have 4 Billions bytes of memory so I expect no problems.

About the other question, I found this example:
from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision
It is explained in the manual.
Reply
#9
it looks like those limits will not obstruct my needs.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020