-1

I am working on a program that outputs the condition number of a big matrix, so I used the Power Method to get the Largest EigenValue, but the values are large numbers (float) larger than 1*10^310, and in the end the values become "Infinity", I tried the decimal module but it's the same. How can I store those large float values? Or maybe another method that uses shorter values? (I'm not allowed to use any module that helps explicitly the proccess as Numpy)

  • Are you using numpy? – OneCricketeer Nov 18 '20 at 22:59
  • No, I'm not using any module (the decimal module doesn't work for me) – Samuel Axel Nov 18 '20 at 23:02
  • Try using fractions module instead – Azat Ibrakov Nov 18 '20 at 23:04
  • 1
    I think if you are doing linear algebra type functions, numpy / scipy would be useful than standard lib – OneCricketeer Nov 18 '20 at 23:06
  • mpmath is a free (BSD licensed) Python library for real and complex floating-point arithmetic with arbitrary precision look [here](http://mpmath.org/) – recurseuntilfor Nov 18 '20 at 23:07
  • I am not allowed to used any modules – Samuel Axel Nov 18 '20 at 23:07
  • 4
    @SamuelAxel that's 100% _critical_ information to put in your original question, since it _significantly_ changes the landscape of possible answers. – Random Davis Nov 18 '20 at 23:08
  • can you divide out common denominators in your matrix? – anon01 Nov 18 '20 at 23:08
  • you will be better served showing exactly the code you are trying to run. I'm skeptical you would need values that large for this – anon01 Nov 18 '20 at 23:10
  • 2
    @SamuelAxel - My answer obviously isn't what you want given the constraint of not being able to use a module...or can you use the `decimal` package? You say two conflicting things...that you can't use any modules and that `decimal` didn't work for you. If you can use `decimal`, why didn't it work for you? BTW, you should put all this information in your question. - Why don't you show us your code? – CryptoFool Nov 18 '20 at 23:13

2 Answers2

2

Don't work with floating point values if you can help it; they are very difficult to reason about and will bite you!

Whenever you are trying to work with floats, especially ones with lots of digits, you should consider how you can shift it into an integer range and if you have invalid or needless accuracy beyond the floating part of your value

  • perhaps into a bigger int such as 10**400 or 10**100000, which should provide plenty of room for your floating point digits, while allowing you to work in the integer space
  • directly convert or scale down, discarding digits beyond the decimal point (consider how accurate the measurement really is)
>>> int(1.0 * 10) * 10**999  # divide off 10**690 later or note in units
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> int(1.0 * 10**10)  # multiply by 10**300 later or note in units
10000000000

Practically, this is why you would want scientific notation - don't store the data with all its digits if you don't need them, keep the smallest amount you need and a second multiplier for the size factor (scientific notation does use a floating-point, but the idea is the same for integers)

Then, rather than working with floating points, you can recall the multiplier(s) at the end when you're done with your math (even multiplying them out separately)

It may even be sufficient to remove a significant portion of the digits entirely in some regular manner, and display the factor in the post-calculation units for whom or whatever is consuming the data


While this question is about large numbers, even decimal.Decimal unfortunately does not handle the small bits of floating points the way one might expect, as they're subject to some aliasing from how they're stored

https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754:_floating_point_in_modern_computers

This is problematic with normal python floats, and so extends to Decimals, even of a size you may expect to see in normal use!

>>> 9007199254740993.0
9007199254740992.0
>>> Decimal(9007199254740993.0)  # NOTE converted to float before Decimal
Decimal('9007199254740992')

Adapted from Which is the first integer that an IEEE 754 float is incapable of representing exactly?

Example to the original question

>>> a = Decimal(10**310) * Decimal(1.0)
>>> b = Decimal(1)
>>> a + b - a
Decimal('0E+283')

Further examples

>>> a = Decimal(10**310)
>>> b = Decimal(0.1)
>>> a + b - a
Decimal('0')
>>> a
Decimal('10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
>>> b
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> 10**-100
1e-100
>>> Decimal(10**-100)
Decimal('1.00000000000000001999189980260288361964776078853415942018260300593659569925554346761767628861329298958274607481091185079852827053974965402226843604196126360835628314127871794272492894246908066589163059300043457860230145025079449986855914338755579873208034769049845635890960693359375E-100')
>>> 10**-1000
0.0
>>> Decimal(10**-1000)
Decimal('0')
ti7
  • 16,375
  • 6
  • 40
  • 68
  • I don't know why you would assume what accuracy is needed in someone else's problem – anon01 Nov 18 '20 at 23:12
  • @anon01 I don't mean that they don't need that precision, but that they don't need it to be a floating-point value. Instead, knowing something of their needed accuracy, they should be able to shift it into the integer space! – ti7 Nov 18 '20 at 23:19
  • 1
    This may be useful and appropriate in certain cases, but I totally disagree with this as a general principle. Why??? Readability and Bugs! There's no reason not to use the `decimal` package if you're doing a bunch of real operations on really big numbers. Having to allow for adding and removing extra powers of 10, and making sure that it's obvious what you're doing across multiple levels of your code, is just crazy. What is your justification for all of the pain that your method requires that you take (again, if you're talking about the general case)? – CryptoFool Nov 18 '20 at 23:23
  • 1
    @anon01 NASA uses pi to 15 digits to calculate Voyager 1's position to within about 2 inches. At a certain point, you're likely to have much more precision than you are accuracy. The ratio of the size of the observable universe to the Planck length is about 10^61, so there aren't many math problems likely to need 310 digits of precision. – Kirk Strauser Nov 18 '20 at 23:23
  • @Steve I added more about why one should still be very wary when working with big floats and `decimal`! – ti7 Nov 18 '20 at 23:52
  • That helps to explain your argument...why you might want to go your way. But I still don't think it justifies all the pain. The only practical problem I find with the floating point issues you raise is when you want to compare two floats for equality. It is admittedly a pain to have to apply a delta, although a simple helper function makes it pretty painless. - but it can introduce insidious bugs if you're not careful. – CryptoFool Nov 18 '20 at 23:59
  • @Steve I'm afraid I must highlight the `a + b - a` examples, which I think absolutely justify any conversion pain. It's extraordinarily precarious to reason about floating-point values! – ti7 Nov 19 '20 at 00:09
2

You want to use the decimal module:

from decimal import Decimal

x = Decimal('1.345e1310')
y = Decimal('1.0e1310')
print(x + y)

Result:

2.345E+1310
CryptoFool
  • 21,719
  • 5
  • 26
  • 44