# Any way to correct the round off errors?

18 messages
Open this post in threaded view
|
Report Content as Inappropriate

## Any way to correct the round off errors?

 Hello everyone, When subtracting in Erlang: 0.92915-0.92945 we should get -0.0003 but Erlang gives: -2.9999999999996696e-4   (when doing 92915-92945 Erlang gives -30 so that's ok). Anyway to make make it give -0.0003 ?, and in general make it give more accurate answers? Regards, -Gene
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 For the record, I just tested the same math in Python and Ruby.  Same   result.  Java probably would as well.  They all represent real numbers   as IEEE 754 floating point numbers. The error you're seeing is because the fractions are represented as   binary fractions.  The only way you're going to get "precise" numbers   is to use fixed-point arithmetic. Keep in mind that accurate is in the eye of the beholder.  While you   want to represent 3/10000 (which would be more accurate with base-10   fixed point arithmetic), if you wanted something more like 1/65536,   floating point would be dead-on accurate, but fixed point base-10   would have error. Here's a partial discussion that may be of use.  I probably should put   implementing a decimal module on my list of things to do, though,   because this is hardly a solved problem (and would be extra useful for   handling money values). http://www.trapexit.org/forum/viewtopic.php?p=44093On Sep 20, 2009, at 4:35 AM, G.S. wrote: > Hello everyone, > > When subtracting in Erlang: 0.92915-0.92945 we should get -0.0003   > but Erlang > gives: -2.9999999999996696e-4   (when doing 92915-92945 Erlang gives   > -30 so > that's ok). > > Anyway to make make it give -0.0003 ?, and in general make it give   > more > accurate answers? > > Regards, > -Gene -- Jayson Vantuyl [hidden email]
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by G.S.-2 G.S. wrote: > Hello everyone, > > When subtracting in Erlang: 0.92915-0.92945 we should get -0.0003 but Erlang > gives: -2.9999999999996696e-4   (when doing 92915-92945 Erlang gives -30 so > that's ok). > > Anyway to make make it give -0.0003 ?, and in general make it give more > accurate answers? Your computer hardware cannot represent 0.0003. [vlm@nala:~]> cc -o c c.c && ./c -0.000300 -0.00029999999999999997 [vlm@nala:~]> cat c.c #include int main() {         double d = -0.0003;         printf("%f\n", d);         printf("%.20f\n", d); } [vlm@nala:~]> So, Erlang does not give you less accurate numbers. Erlang just gives you a differently formatted decimal representation of a binary number which can't be 0.0003. -- vlm ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 Lev Walkin wrote: > G.S. wrote: >> Hello everyone, >> >> When subtracting in Erlang: 0.92915-0.92945 we should get -0.0003 but >> Erlang >> gives: -2.9999999999996696e-4   (when doing 92915-92945 Erlang gives >> -30 so >> that's ok). >> >> Anyway to make make it give -0.0003 ?, and in general make it give more >> accurate answers? > > Your computer hardware cannot represent 0.0003. > > [vlm@nala:~]> cc -o c c.c && ./c > -0.000300 > -0.00029999999999999997 > [vlm@nala:~]> cat c.c > #include > > int main() { >     double d = -0.0003; >     printf("%f\n", d); >     printf("%.20f\n", d); > } > [vlm@nala:~]> > > > So, Erlang does not give you less accurate numbers. > Erlang just gives you a differently formatted decimal > representation of a binary number which can't be 0.0003. > It's not the computer hardware, but the representation used for floating point numbers... You can come up with your own library of arithmetic functions where you represent decimals as you wish. Of course you will have to trade performance for the desired accuracy. Java for example has BigDecimals for this cause:  >java Zed -0.00030 ------------- import java.math.BigDecimal; class Zed {   public static void main(String[] args) {     BigDecimal x = new BigDecimal("0.92915");     BigDecimal y = new BigDecimal("0.92945");     System.out.println( x.subtract(y) );   } } ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by G.S.-2 > When subtracting in Erlang: 0.92915-0.92945 we should get -0.0003 but Erlang > gives: -2.9999999999996696e-4   (when doing 92915-92945 Erlang gives -30 so > that's ok). > > Anyway to make make it give -0.0003 ?, and in general make it give more > accurate answers? That's an interesting question. The other replies tell us it's a 64 bit Double floating point representation : http://en.wikipedia.org/wiki/Double_precision_floating-point_formatwhich has, according to Wikipedia, "about 16 decimal digits" of precision from the 52 bits. Their example is correct up to 16 digits : 0.33333333333333331482                   *    1234567890123456 but yours is only correct up to 13 digits : 2.9999999999996696e-4               * 1 234567890123456 so we probably shouldn't trust more than 12 digits of precision because each calculation will lose some precision from the end of the number. Different calculations will lose different amounts of precision and very long sequences of calculations could reduce the number of correct digits below 12. You might think it would be nice to have every calculation keep a record in the double of how many digits we can trust. If we did this the output routine could give the exact answer to your calculation. But this would be very difficult to calculate and would consume processor power at every step. So instead floating point routines rely on the programmer to know about floating point accuracy and you always have to round the output appropriately. If you round that answer to 12 digits it is exactly correct. In general always use a number representation that can cope with numbers much bigger and with much more accuracy than you are expecting because bugs in this area are nasty. Richard. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 On 20 Sep 2009, at 17:22 , Witold Baryluk wrote: > > If you want something which calculates correctly in decimal number,   > use > integers multiplied with some 10^k power. It is called fixed point > arithmetic. Or use a decimal floating-point library such as gmp. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by Witold Baryluk Witold Baryluk wrote: >> so we probably shouldn't trust more than 12 digits of precision because >> each calculation will lose some precision from the end of the number. > Substraction (and addition) can lose  any number of digits you wish. > I would be horrified if I added two doubles 0.111111111111 + 0.111111111111 and got 0.225745048327 I have no idea what the IEEE standard specifies, but I can't imagine anybody ever implementing or using a version that gave this answer. I would expect at least twelve significant digits of precision. 0.2222222222228765767 But if I added these two doubles 0.111111111111 + 0.000000000000111111111111 I wouldn't be surprised to get 0.111111111111343786587698 which gives the right answer to 12 significant digits, but loses all of the significant digits in the second number.The same for subtraction. Richard. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by Masklinn Dnia 2009-09-20, nie o godzinie 18:06 +0200, Masklinn pisze: > On 20 Sep 2009, at 17:22 , Witold Baryluk wrote: > > > > If you want something which calculates correctly in decimal number,   > > use > > integers multiplied with some 10^k power. It is called fixed point > > arithmetic. > Or use a decimal floating-point library such as gmp. Sure. But considering that Erlang already have arbitrary precision integers, writing few functions for add/sub/mul/div isn't very hard :) It will be more portable than linking to gmp, :) Still operations will need to be called explicitly, because Erlang doesn't have operator overloading. ;) -- Witold Baryluk signature.asc (205 bytes) Download Attachment
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by Richard Kelsall Dnia 2009-09-20, nie o godzinie 17:08 +0100, Richard Kelsall pisze: > Witold Baryluk wrote: > >> so we probably shouldn't trust more than 12 digits of precision because > >> each calculation will lose some precision from the end of the number. > > Substraction (and addition) can lose  any number of digits you wish. > > > I would be horrified if I added two doubles > > 0.111111111111 + > 0.111111111111 > > and got > > 0.225745048327 > > I have no idea what the IEEE standard specifies, but I can't imagine > anybody ever implementing or using a version that gave this answer. > I would expect at least twelve significant digits of precision. > > 0.2222222222228765767 > > But if I added these two doubles > > 0.111111111111 + > 0.000000000000111111111111 > > I wouldn't be surprised to get > > 0.111111111111343786587698 > > which gives the right answer to 12 significant digits, but loses all > of the significant digits in the second number.The same for subtraction. > > > Richard. Maybe i written not clearly. I was thinking more about such situation: > 0.111111111111 - 0.111111111113. -1.9999973899231804e-12 -0.000000000001999997389923180435 > It have only one correct significant decimal digit. -- Witold Baryluk signature.asc (205 bytes) Download Attachment
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 Witold Baryluk wrote: > Maybe i written not clearly. I was thinking more about such situation: > >> 0.111111111111 - 0.111111111113. > -1.9999973899231804e-12 > -0.000000000001999997389923180435 > > It have only one correct significant decimal digit. > You are quite right. I hadn't thought of that one. Richard. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by Witold Baryluk On 20 Sep 2009, at 18:12 , Witold Baryluk wrote: > Dnia 2009-09-20, nie o godzinie 18:06 +0200, Masklinn pisze: >> On 20 Sep 2009, at 17:22 , Witold Baryluk wrote: >>> If you want something which calculates correctly in decimal number, >>> use >>> integers multiplied with some 10^k power. It is called fixed point >>> arithmetic. >> Or use a decimal floating-point library such as gmp. > > Sure. But considering that Erlang already have arbitrary precision > integers, writing few functions for add/sub/mul/div isn't very hard :) Arbitrary precision integers are quite different beasts (and easier to   handle) than arbitrary precision floats. Most languages with native   arbitrary precision integers (python, ruby, Haskell's Integer type, â€¦)   tend to relegate arbitrary precision floats to libraries, either   stdlib or third-party, and pretty much systematically rely on IEEE754   floating-points natively (though they might have fraction types   between integer and reals). > It will be more portable than linking to gmp, :) Not necessarily (gmp is quite damn portable), and it would be much   harder to handle correctly. FWIW, Python's decimal module is 2500   lines of pure python. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by Richard Kelsall Hynek Vychodil wrote: > Interesting, but seems well for me. > > \$ erl > Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] > [hipe] [kernel-poll:false] > > Eshell V5.7.2  (abort with ^G) > 1> 0.111111111111 + 0.111111111111. > 0.222222222222 > 2> 0.111111111111 - 0.111111111111. > 0.0 > 3> 0.111111111111 + 0.11111111111. > 0.222222222221 > 4> 0.111111111111 - 0.11111111111. > 1.0000056338554941e-12 Yes, as far as I know Erlang is working perfectly. I was only speaking hypothetically. Sorry for the noise. Richard. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by G.S.-2 On Sep 20, 2009, at 11:35 PM, G.S. wrote: > Hello everyone, > > When subtracting in Erlang: 0.92915-0.92945 we should get -0.0003   > but Erlang > gives: -2.9999999999996696e-4   (when doing 92915-92945 Erlang gives   > -30 so > that's ok). > > Anyway to make make it give -0.0003 ?, and in general make it give   > more > accurate answers? Erlang *DID* give you the most accurate answer possible. Here is a little C program. m% cat zoo.c #include int main(void) {      double const x = 0.92915;      double const y = 0.92945;      printf("0.92915           =  %.20f\n", x);      printf("          0.92945 =  %.20f\n", y);      printf("0.92915 - 0.92945 = %.20f\n", x - y);      return 0; } m% cc zoo.c m% a.out 0.92915           =  0.92915000000000003144            0.92945 =  0.92944999999999999840 0.92915 - 0.92945 = -0.00029999999999996696 The problem is that the numbers 0.92915 an 0.92945 CANNOT BE REPRESENTED EXACTLY IN BINARY FLOATING-POINT. There's a new standard for decimal floating-point, which I believe is supported in shipping versions of the z/Series and POWER machines, and it will take a lot of the nasty surprise out of things like this. The answer you got involved four steps where round-off error can occur:         decimal -> binary         decimal -> binary again         subtraction         binary -> decimal Giving any answer than what Erlang gave would be giving WRONG answers. If you want to *print* the result to a lower precision, so that the effects of round-off error are (sometimes) (partially) hidden (if you are lucky), that's easy. The interactive top level will already print this number as -3.00000e-4.  You can use vaguely C-like formats such as io:fwrite("~.6g", [-0.00029999999999996696]). Note that this doesn't change what the answer *is* (it's already as good as you have any right to expect), it just changes *how it is displayed*. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 In reply to this post by Richard Kelsall On Sep 21, 2009, at 4:08 AM, Richard Kelsall wrote: > Witold Baryluk wrote: >>> so we probably shouldn't trust more than 12 digits of precision   >>> because >>> each calculation will lose some precision from the end of the   >>> number. >> Substraction (and addition) can lose  any number of digits you wish. > I would be horrified if I added two doubles > > 0.111111111111 + > 0.111111111111 > > and got > > 0.225745048327 Yes, but you missed the point.  Those two numbers have the same sign.  Witold Baryluk was talking about subtraction. Adding two numbers of opposite signs does subtraction. If you have x+y+e and x+z+f, where x is the "common" part of two similar numbers, y and z are the true differences, and e and f are errors, then         (x+y) - (x+z) = y-z but (x+y+e) - (x+z+f) = y-z + e-f and the errors  e, f that were small compared with x may be extremely large compared with y-z. Read for example http://www.cs.princeton.edu/introcs/91float/specifically the section beginning "Catastrophic cancellation. Devastating loss of precision when small numbers are computed from large numbers by addition or subtraction." > I have no idea what the IEEE standard specifies, Well, shouldn't you _find out_?  I mean, before using something as weird (but widespread) as floating point arithmetic, shouldn't you take the trouble to find out what it is *supposed* to do?  The IEEE 754 standard is small and tolerably clear; there are drafts and summaries and review articles about it all over the web. > but I can't imagine > anybody ever implementing or using a version that gave this answer. They don't.  Nobody ever suggested it would. The original example subtracts two numbers with similar values. Any fixed-width floating point system ever built is going to have trouble with that.  IEEE floating-point arithmetic was designed with exceptional care and a demand for good behaviour even when that conflicted with speed. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org
Open this post in threaded view
|
Report Content as Inappropriate

## Re: Any way to correct the round off errors?

 On 21 Sep 2009, at 03:50 , Richard O'Keefe wrote: > > The IEEE 754 standard is small and tolerably clear; > there are drafts and summaries and review articles about it > all over the web. First and foremost being Goldberg's "What Every Computer Scientist   Should Know About Floating-Point Arithmetic" (http://docs.sun.com/source/806-3568/ncg_goldberg.html  ) which is often considered the most basic knowledge requirement   before any discussion of IEEE-754 floats. ________________________________________________________________ erlang-questions mailing list. See http://www.erlang.org/faq.htmlerlang-questions (at) erlang.org