-1

I'm having this issue in python with float arithmetic. The equation I'm solving goes as follows:

-a *((x-m)*110.0*(1-m))**b +a*((x-m)*110.0*(1-m))**c
a is a really large positive number (in the hundred thousands)
b is 1.0000002
c is 0.9999998

When I do this in excel I get accurate results but when I do it in python I get completely inaccurate results.

The results are exactly the same for each separate part until I multiply by -a and a. So ((x-m)110.0(1-m))**b and ((x-m)110.0(1-m))**c are exactly the same as their excel calculated values but when they're multiplied by the large number they completely change.

How do I do this? do I have to use a different language? Is this problem only in python or is it in all languages?

Edit: It is the exact same equation in excel as in python. Exactly the same. The numbers are also the same until I multiply by a and -a. then they are both off by 5 point something. The answer in excel is around 0.47 for x=0.5 and m = 0.265 while the answer for python is around -0.67

Obito
  • 391
  • 3
  • 8
sbeleidy
  • 323
  • 3
  • 11
  • 20
  • 3
    -1: What results do you get, and what results do you expect? Have you tried simplifying the equation? Have you tried comparing intermediate results? – Oliver Charlesworth Jul 03 '11 at 13:09
  • 1
    "completely inaccurate"? Can you show what you got? – Ned Batchelder Jul 03 '11 at 13:28
  • Echo the above. Show us the equations you used in excel, the results in excel, and the results in python. – David Hammen Jul 03 '11 at 13:36
  • 1
    @Oli: +1 for "Have you tried simplifying the equation". @sbeleidy: This simplifies very nicely using simple reduction rules. It simplifies even further using the hyperbolic sine. – David Hammen Jul 03 '11 at 13:38
  • I apologize but I dont understand how I can show you the results in excel. I place the same equation and in python I get a negative number and in excel I get a different positive number. – sbeleidy Jul 04 '11 at 07:27
  • Does Python have decimals, by any chance? – Joey Jul 04 '11 at 08:53

5 Answers5

4

mpmath can be the answer

Mpmath is a pure-Python library for multiprecision floating-point arithmetic. It provides an extensive set of transcendental functions, unlimited exponent sizes, complex numbers, interval arithmetic, numerical integration and differentiation, root-finding, linear algebra, and much more.

http://code.google.com/p/mpmath/

Ant
  • 5,151
  • 2
  • 26
  • 43
  • Just tried mpf() and its still not working... giving the same value, and if i change the dps to a larger number it becomes less accurate instead of more accurate – sbeleidy Jul 03 '11 at 13:55
  • 1
    I think your problems lie elsewhere, sbeleidy. Do what we asked: Show your equations in excel, your equations in python, and some typical results that do not match. – David Hammen Jul 03 '11 at 14:01
4

It is quite hard to understand what precision you are looking for but i think that you can also take a look at the decimal module. -

It offers several advantages over the float datatype:

Decimal “is based on a floating-point model which was designed with people in mind, and necessarily has a paramount guiding principle – computers must provide an arithmetic that works in the same way as the arithmetic that people learn at school.” – excerpt from the decimal arithmetic specification.

Decimal numbers can be represented exactly. In contrast, numbers like 1.1 and 2.2 do not have an exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.

The exactness carries over into arithmetic. In decimal floating point, 0.1 + 0.1 + 0.1 - 0.3 is exactly equal to zero. In binary floating point, the result is 5.5511151231257827e-017. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.

The decimal module incorporates a notion of significant places so that 1.30 + 1.20 is 2.50. The trailing zero is kept to indicate significance. This is the customary presentation for monetary applications. For multiplication, the “schoolbook” approach uses all the figures in the multiplicands. For instance, 1.3 * 1.2 gives 1.56 while 1.30 * 1.20 gives 1.5600.

Artsiom Rudzenka
  • 27,895
  • 4
  • 34
  • 52
2

Floating point arithmetic is by definition not completely 100% accurate, because values are represented as fractions. Have a look at the article about Python float limitations, as well as another, more general article.

driis
  • 161,458
  • 45
  • 265
  • 341
1

If you just want arbitrary precision arithmetic, use the Fraction class within the fractions module, which is part of the standard library. When you're done with your calculations, you can convert it to a float (if you must). Unfortunately, the resultant float may not be arbitrary precision, but all the calculations up until the conversion to a float will be, and thus your float will likely be more accurate than if you were using floats the whole time.

Really, if you don't care about the visual, just keep the number a Fraction the whole time and your problem is solved. If you do care about seeing a decimal point, you'll need to realize that arbitrary precision in that case is going to be a rather involved process, because then you have to deal with repeating values (like a third is a bunch of threes forever, after 0.). Nevertheless, there are people out there who try to solve the problem. Getting it accurate up to a certain decimal point should certainly be possible, but don't expect more than that if you're not using Fractions.

Fractions have numerators and denominators (which are stored as longs, I believe, and longs in Python are already arbitrary precision; so, you can have numbers as big as you like for both the numerator and the denominator). I wrote some code for converting fractions from 1234/12 style to 2 3/4 style. But, I don't want to give it a CC license by posting it here (I'd rather a real software license, such as MIT). So, you'll have to let me know if you're interested.

Here are examples of how to use fractions.Fraction:

from fractions import Fraction
x=Fraction("2.234532456345265356356356354624356356235635634563563565635645") #You can add string numbers of any value.
y=Fraction(1, 3234524352345) #This is one 3234524352345th 
x+=5 #adding five (The five doesn't have to be a Fraction object, but the result will be one.)
y=x/y #Dive x by y.
x=float(x) #Converting it into a float

Anyway, you can treat them just like any other kind of number. You can convert things to fractions the same as you would to integers (e.g. Fraction(4.2343) will convert the float to a Fraction). You can round them, or whatever, too.

I find that Fraction class to be vastly under-represented. I use it a lot. It's awesome.

Brōtsyorfuzthrāx
  • 4,387
  • 4
  • 34
  • 56
  • Note: Converting the first argument to a string is really necessary to prevent floating point rounding errors: `float(Fraction(5.6) - 5)` is still `.5999...`, but `float(Fraction("5.6") - 5)` is `0.6` – Bryce Guinta Feb 19 '18 at 20:05
1

I tried this using the following values (I chose something in the hundred thousands for a as that is as specific as your description got):

>>> a = 500000.0
>>> b = 1.0000002
>>> c = 0.9999998
>>> x = 0.5
>>> m = 0.265

Calculating the inner value:

>>> inner = (x - m) * 110.0 * (1 - m)
>>> print inner
18.99975

And the exponents:

>>> exponent1 = inner**b
>>> exponent2 = inner**c
>>> print (exponent1, exponent2)
(18.999761188674185, 18.999738811332392)

Multiplying the exponents by a:

>>> aexp1 = -a * exponent1
>>> aexp2 = a * exponent2
>>> print (aexp1, aexp2)
(-9499880.5943370927, 9499869.4056661967)

And the final answer:

>>> final = aexp1 + aexp2
>>> print final
-11.188670896

What do you get for these values in Excel? Alternatively, post what value of a you actually use and I'll update my answer.

Now, you've dodged this issue somewhat when people asked you in their comments, but if you want us to figure out why it is different in Excel, you'll need to tell us exactly how you are doing the calculations in Excel. This means the formulas you are putting into the cells to generate the values. Telling us they're exactly the same is not useful as it doesn't give us anything to go on. From here, my guess is that they aren't in fact the same, as I think it unlikely floating point errors or the like would be the cause of an error the size you report in your question. It is more likely that you have a typo or misunderstanding somewhere.

Blair
  • 15,356
  • 7
  • 46
  • 56
  • 1
    `final = aexp1 + aexp2`: There is an inherent loss of precision here because `aexp1` and `aexp2` are nearly equal to one another in magnitude but have opposite signs. How much error? The expression can be rewritten as `-2*a*inner*math.sinh(2e-7*math.log(inner))`, thereby avoiding the precision loss problem. The result from this is -11.1886708992 (compare to Blair's -11.188670896). The subtraction loses 6 decimal places, assuming python uses IEEE double precision underneath the hood. **NOTE WELL**: This is not the kind of error to which sbeleidy aluded. – David Hammen Jul 04 '11 at 13:34