In Python, is there any way to multiply a float with a very large integer?
As an example, I tried print (10**100000) * 1.414
and it gave me:
OverflowError: long int too large to convert to float
Note that the values (the float and that large number) can be anything. More importantly, I want the exact value (rounded to nearest integer) of expression.
Please provide any solution.
If you're looking for the exact value, this means you must have access to 1.414 as a string (otherwise, the value stored in memory isn't exact either).
import decimal
float_string = '1.614' # to show that rounding works
exponent = 100000
decimal.getcontext().prec = exponent + 1
c = 10 ** exponent + 1
d = decimal.Decimal(float_string) * c
print d #1614000.....000002
Convert the float to an integer ratio:
value = 1.414
large = 10**100000
a, b = value.as_integer_ratio()
number, residual = divmod(large * a, b)
number += residual*2 >= b
Edit 2:
Ok, I see what you're after:
import mpmath
mpmath.mp.dps = 100005
i = int(mpmath.mpf("1.414") * 10 ** 100000)
print(str(i)[:10]) # 1414000000
print(len(str(i))) # 100001
print(str(i)[-10:]) # 0000000000
print(str(i).count("0")) # 99997
And for #Stefan:
int(mpmath.mpf("1.414") * (10 ** 100000 + 1000))
returns
14140000000000000 ... 000000000001414 # string contains 99993 0s
Since you accept integer approximations, here is a native solution:
def getint(x, y, z):
z_nu, z_de = z.as_integer_ratio()
return ((x**y) * z_nu) // z_de
Usage:
>>> getint(2, 3, 5.)
40
>>> getint(10, 100000, 1.414)
1413999999999999923616655905789230018854141235351562500000000... # truncated
Related
This question already has answers here:
Why are these numbers not equal?
(6 answers)
Closed 1 year ago.
this is the code.
import math
a = math.pow(10,100)
b = 10 ** 100
c = 10 ** 100
print(a==b) # false
print(a-b==0) # true
I know the math.pow is not correct while the number is too large. but how to understand the next point that a == b is not the same as a-b == 0 ?
my python version is 3.9.6 64bit
This is because of floatingpoint error that can happen to large or small float number. See more info on https://docs.python.org/3/tutorial/floatingpoint.html
Float numbers is stored as an 53 bit. So this problem will not happen to float numbers lower than 4503599627370496. See https://en.wikipedia.org/wiki/IEEE_754-1985 for more info.
import math
a = math.pow(10,100)
b = 10 ** 100
print(type(a)) # float
print(type(b)) # int
We can see that a is an float and b is an int.
print(int(a)) # 10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104
If we convert a into an int we will see that the number has changed and is no longer math.pow(10,100)
print(a==b) # false
print(int(a)==int(b)) # false
print(float(a)==float(b)) # true
print(a-b==0) # true
If we try to convert both to int it will be the same as a==b but if we convert both to float it will work. That is because both numbers will get the same conversion error.
When we do print(a-b==0) this will be converted correctly.
math.pow, value type is float
a = math.pow(10,100)
b = float(10 ** 100)
a==b is true
For large numbers, the precision is low that is why one is True, the other is False, if you try with a smaller number, you will see that both will evaluate to be True:
>>> math.pow(10,15)
1000000000000000.0
>>> 10**15
1000000000000000
>>> math.pow(10,15)==10**15
True
>>> math.pow(10,20)
1e+20
>>> 10**20
100000000000000000000
>>> math.pow(10,20) == 10**20
True
But if you look at some larger numbers represented by exponent:
>>> math.pow(10,50)
1e+50
>>>10**50
100000000000000000000000000000000000000000000000000
>>> math.pow(10,50)==10**50
False
If you try to convert it to integer, you'll see that the number just changes:
>>> int(math.pow(10,50))
100000000000000007629769841091887003294964970946560
For larger numbers (like you've used math.pow(10, 100)), a-b == 0 returns False because of Floating point arithmetic.
math.pow() - Converts its arguments to float type
From the Docs:
Unlike the built-in ** operator, math.pow() converts both its arguments to type float.
** and pow() - Returns an Integer.
Use ** or the built-in pow() function for computing exact integer powers.
import math
a = 10**2
b = math.pow(10,2)
c = pow(10,2)
print(f'a: {a}\nb: {b}\nc: {c}')
print(a==b)
print(a-b==0)
a: 100
b: 100.0
c: 100
True
True
From above results, you can see what types they return.
Also a-b == 0 returns True in this case since the numbers are small.
For example, if I have:
12.43564
I'd like to be able to get 43564 as an int. Or, if the float has many decimal places, it would be OK to just get the first N decimals as integer. For example, if N is 3, for 12.43564 I would then get 435. Unfortunately, I cannot just convert the number to a string as I need to use this in a numba compiled function, where the conversion of a float to a string is not possible as per this open issue.
Is there a way to do this?
Typecast it to a string, split on the period, get the N digits you want.
>>> x = 1.23456789
str(x)
>>> str(x)
'1.23456789'
>>> str(x).split('.')
['1', '23456789']
>>> str(x).split('.')[1][:4]
'2345'
Based on edit,
Substract the int part. Multiply by 10000 to get the first 4.
>>> (x - int(x)) * 10000
2345.678899999999
>>> int((x - int(x)) * 10000)
2345
Convert it to a string, split it at the decimal, and slice it:
x = 12.43564
print(str(x).split(".")[1][:3])
Note that slicing won't throw any errors if you try to get extra digits:
str(x).split(".")[1][:1000]
will just return 43564
Here's an approach that works with negative numbers too
def digits(x,N):
return int((abs(x) % 1) * 10**N)
print(digits(1.23456,2))
print(digits(-1.23456,3))
print(digits(1.23,5))
Gives:
23
234
23000
Without converting to string, you can try numpy.modf:
> np.modf(d)
(0.43563999999999936, 12.0)
> int(np.modf(d)[0] * 1e3)
435
Here's a nice and purely mathematical approach that doesn't require any ext lib:
n = 12.43564
result = n % int(n)
while not int(result) or int(result) % 10:
result *= 10
result = int(result / 10)
I am playing around with some RSA crypto calculations and one of them is calculating
very-large-number**(1/3)
where very large number is 100 digits. I need the result as hexadecimal in the end to get the final result.
I have tried the usual float.hex() hex(int(n)) and even some of the prosed solutions from here Dealing with very large hex numbers in python
but the result I get is either in scientific format (xx.xxxx+40) or the last half of the outout is all 0 (which I know is not correct)
Example:
>>> n=14887716705766614226302331656748546195328906880296894322596715261404953788693951344841626882745910926946567107240171862117
>>> ct=n**(1/3)
>>> ct.hex()
'0x1.212d39ed89671p+134'
>>> print(ct)
2.4600430019674926e+40
>>> print(ct.hex())
0x1.212d39ed89671p+134
hex(int(ct))
'0x484b4e7b6259c400000000000000000000'
>>> int(ct)
24600430019674926067273894051435979472896
so how do I get the hex value out ? the first part)0x484b4e7b6259c) from hex(int(ct)) is correct so this seem to indicate precision error.
I have also tried with numpy:
>>> import numpy as np
>>> x=np.longdouble(14887716705766614226302331656748546195328906880296894322596715261404953788693951344841626882745910926946567107240171862117)
>>> float_formatter='{e:f}'.format
>>> np.set_printoptions(formatter={'float_kind':float_formatter},precision=128)
>>> ct=np.cbrt(x)
>>> np.cbrt(x)
2.4600430019675053399e+40
>>> print(ct)
2.4600430019675053399e+40
Edit:
the actual result for the calculations should be: 24600430019675053398291607284547696341373 before hex which should turn into 0x484B4E7B625A2D53644D2D64644F72317D as hex
The problem is that while Python integers are multi-precision numbers, floats are only 64 bits IEEE 754 floating point numbers and have a precision limited to 15 or 16 decimal digits.
That means that the floating point n ** (1/3) operation will only give an approximation.
But you could use Newton method to find a more accurate solution of the equation x**3 = n:
def sqr3(n):
s0 = int(n ** (1/3))
s1 = 0
while True:
s1 = s0 + (n - s0 **3) // 2 // s0 // s0
if s1 ** 3 == n:
break
if (s0 - 1 <= s1 <= s0 + 1):
# should search further whether s0 or s1 (or maybe next iteration)
# would be the best one...
break
s0 = s1
return s1
It gives for sqr3(n): 24600430019675053398291607284547696341373 which is the exact solution.
Doing a quick check with an existing online converter, your two outputs are in fact the same number
'0x484b4e7b6259c400000000000000000000'
equals
24600430019674926067273894051435979472896
In python, I need to get the rounded down logarithm of positive integers for base 2, including big numbers.
However, since floating point math is used, I might get bad results, for example:
>>> import math
>>> int(math.log(281474976710655, 2))
48
However:
>>> 2 ** 48
281474976710656
So the correct result, rounded down, should be 47.
How can I get the correct value?
In Python 3, integers have a .bit_length method, so you should use that to get your rounded down base 2 logarithm.
Here's a short demo:
m = 2 ** 1000
for n in (281474976710655, m-1, m, m+1):
a = n.bit_length() - 1
b = 2 ** a
print(a, b <= n < 2 * b)
output
47 True
999 True
1000 True
1000 True
In python 3 ints even have an efficient .bit_length() method!
>>> (281474976710655).bit_length()
48
>>> (281474976710656).bit_length()
49
In python 2, instead of using floating point math, count the number of bits:
def log2(n):
assert n >= 1
return len(bin(n)) - 3 # bin() returns a string starting with '0b'
(Edited following this comment)
I have found two ways of taking floors in Python:
3.1415 // 1
and
import math
math.floor(3.1415)
The problem with the first approach is that it return a float (namely 3.0). The second approach feels clumsy and too long.
Are there alternative solutions for taking floors in Python?
As long as your numbers are positive, you can simply convert to an int to round down to the next integer:
>>> int(3.1415)
3
For negative integers, this will round up, though.
You can call int() on the float to cast to the lower int (not obviously the floor but more elegant)
int(3.745) #3
Alternatively call int on the floor result.
from math import floor
f1 = 3.1415
f2 = 3.7415
print floor(f1) # 3.0
print int(floor(f1)) # 3
print int(f1) # 3
print int(f2) # 3 (some people may expect 4 here)
print int(floor(f2)) # 3
http://docs.python.org/library/functions.html#int
The second approach is the way to go, but there's a way to shorten it.
from math import floor
floor(3.1415)
Beware that taking the floor and casting to an int are not the same thing with negative numbers. If you really want the floor as an integer, you should cast to an int after calling math.floor().
>>> int(-0.5)
0
>>> math.floor(-0.5)
-1.0
>>> int(math.floor(-0.5))
-1
Cast it to int if you don't want a float
int(3.1415 // 1)
from math import floor
def ff(num, step=0):
if not step:
return floor(num)
if step < 0:
mplr = 10 ** (step * -1)
return floor(num / mplr) * mplr
ncnt = step
if 1 > step > 0:
ndec, ncnt = .0101, 1
while ndec > step:
ndec *= .1
ncnt += 1
mplr = 10 ** ncnt
return round(floor(num * mplr) / mplr, ncnt)
You can use positive/negative numbers and float points .1, .01, .001...