[gentoo-user] 69.99 != 69.99

2015-08-22 Thread hw


Hi,

I have the following in a perl script:


  if ($a != $b) {
print e: '$a', t: '$b'\n;
  }


That will print:

e: '69.99', t: '69.99'


When I replace != with ne (if ($a ne $a) {), it doesn't print.


Is that a bug or a feature?  And if it's a feature, what's the explanation?

And how do you deal with comparisions of variables when you get randomly 
either correct results or wrong ones?  It's randomly because this 
statement checks multiple values in the script, and 69.99 is the only 
number showing up yet which isn't numerically equal to itself (but equal 
to itself when compared as strings).




Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Alan McKinnon
On 22/08/2015 15:26, hw wrote:
 
 Hi,
 
 I have the following in a perl script:
 
 
   if ($a != $b) {
 print e: '$a', t: '$b'\n;
   }
 
 
 That will print:
 
 e: '69.99', t: '69.99'
 
 
 When I replace != with ne (if ($a ne $a) {), it doesn't print.
 
 
 Is that a bug or a feature?  And if it's a feature, what's the explanation?
 
 And how do you deal with comparisions of variables when you get randomly
 either correct results or wrong ones?  It's randomly because this
 statement checks multiple values in the script, and 69.99 is the only
 number showing up yet which isn't numerically equal to itself (but equal
 to itself when compared as strings).



Computer languages have a much more exact idea of what equality means
than you do. In your head (because you are human, not silicon) you are
completely comfortable with taking 69.99 and treat8ing it as a string,
or a number, or a mostly-rounded-off floating point number.

The computer does not do it like that. To a computer, the same must be
exactly the same. Two things a little bit different are completely
different (or not equal). And perl has two different operators for
(in)equality:

!= does a numerical comparison. More on this below
ne does a string comparison. When viewed as a bunch of characters, 69.99
and 69.99 are identical.

Now, your comparisons are NOT random. They are entirely predictable, as
long as you know what is going on; you are running into floating point
numbers. And as it turns out, computers never represent these things
exactly (they are NOT integers). Even though they look identical
on-screen, in RAM they will not be (this must be so for perl to do the
print). Maybe they actually resolve to 69.99001 and 69.9900. You
see them as close-as-dammit equal, perl sees them as entirely different.

This is such as huge IT problem that many solutions have been proposed.
You get classes like BigFloat that represent a floating point as an
integer so that equality works, you can round the floats off before
comparing them, or just make the things integers.

The last one is nice: don't represent money as dollars and cents,
represent it as cents or decicents and only divide by 100 (or 1000) when
you finally get to display it.

So how to fix your problem: you are doing what you shouldn't do - trying
equality on floats. Turn them into integers, or round them off, or use
=/= instead of !=


-- 
Alan McKinnon
alan.mckin...@gmail.com




Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread hw



Am 22.08.2015 um 15:43 schrieb Alan McKinnon:

On 22/08/2015 15:26, hw wrote:


Hi,

I have the following in a perl script:


   if ($a != $b) {
 print e: '$a', t: '$b'\n;
   }


That will print:

e: '69.99', t: '69.99'


When I replace != with ne (if ($a ne $a) {), it doesn't print.


Is that a bug or a feature?  And if it's a feature, what's the explanation?

And how do you deal with comparisions of variables when you get randomly
either correct results or wrong ones?  It's randomly because this
statement checks multiple values in the script, and 69.99 is the only
number showing up yet which isn't numerically equal to itself (but equal
to itself when compared as strings).




Computer languages have a much more exact idea of what equality means
than you do. In your head (because you are human, not silicon) you are
completely comfortable with taking 69.99 and treat8ing it as a string,
or a number, or a mostly-rounded-off floating point number.

The computer does not do it like that. To a computer, the same must be
exactly the same. Two things a little bit different are completely
different (or not equal). And perl has two different operators for
(in)equality:

!= does a numerical comparison. More on this below
ne does a string comparison. When viewed as a bunch of characters, 69.99
and 69.99 are identical.


When the value is numerically not 69.99 but something like 69.99001, 
then printing the value should print 69.99001 rather than 69.99.


perl -e 'print 1/3 . \n;' prints 0.333

perl -e 'printf(%34.32f\n, 1/3);' prints 
0.1482961625624739


perl -e 'print (((1/3 == 0.333) ? equal : not equal) . 
\n);' prints not equal


perl -e 'print (((1/3 == 0.0.1482961625624739) ? equal 
: not equal) . \n);' prints Integer overflow in decimal number at 
-e line 1. a couple times


This is random, may it be predictable or not, and what's the integer here?


Now, your comparisons are NOT random. They are entirely predictable, as
long as you know what is going on; you are running into floating point
numbers. And as it turns out, computers never represent these things
exactly (they are NOT integers). Even though they look identical
on-screen, in RAM they will not be (this must be so for perl to do the
print). Maybe they actually resolve to 69.99001 and 69.9900. You
see them as close-as-dammit equal, perl sees them as entirely different.


Why can't it print the number as it is, or at least as it is compared, 
like it should?  If it would, one could see at once what the problem is.



This is such as huge IT problem that many solutions have been proposed.
You get classes like BigFloat that represent a floating point as an
integer so that equality works, you can round the floats off before
comparing them, or just make the things integers.

The last one is nice: don't represent money as dollars and cents,
represent it as cents or decicents and only divide by 100 (or 1000) when
you finally get to display it.


That would add quite a lot of complexity, and the problem should either 
be handled transparently, or the value should be printed as the 
software/computer sees it.  It is a recipe for disaster when you tell 
your computer to print something but it prints something else instead.



So how to fix your problem: you are doing what you shouldn't do - trying
equality on floats. Turn them into integers, or round them off, or use

=/= instead of !=


'=/=' is not an operator in perl?



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread R0b0t1
https://en.wikipedia.org/wiki/Round-off_error
https://en.wikipedia.org/wiki/Machine_epsilon

Either add a tolerance (a - b = t) or compare them as strings as
you've been doing.



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Fernando Rodriguez
On Saturday, August 22, 2015 3:26:56 PM hw wrote:
 
 Hi,
 
 I have the following in a perl script:
 
 
if ($a != $b) {
  print e: '$a', t: '$b'\n;
}
 
 
 That will print:
 
 e: '69.99', t: '69.99'
 
 
 When I replace != with ne (if ($a ne $a) {), it doesn't print.
 
 
 Is that a bug or a feature?  And if it's a feature, what's the explanation?
 
 And how do you deal with comparisions of variables when you get randomly 
 either correct results or wrong ones?  It's randomly because this 
 statement checks multiple values in the script, and 69.99 is the only 
 number showing up yet which isn't numerically equal to itself (but equal 
 to itself when compared as strings).
 

Most languages have a decimal type that you should use when you need exact 
math. I think for perl this is what you want:

http://search.cpan.org/~zefram/Math-Decimal-0.003/lib/Math/Decimal.pm

-- 
Fernando Rodriguez



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Mike Gilbert
On Sat, Aug 22, 2015 at 1:32 PM, Alan McKinnon alan.mckin...@gmail.com wrote:
 I can tell you that equality comparisons on floats are problematic, and
 always will be due to how they are stored (double-precision floats,
 inhernetly inexact). This is not a problem per se, it's a systemic
 side effect of how our computers represent floats i.e. you can't fix
 it as there is nothing to fix

It's not that floats are inherently inexact; it really has to do
with trying to represent a base-10 number in a data structure designed
to hold a base-2 number.

If your number can be represented by some multiple of a power of 2,
equality comparisons will work. If it cannot be, it has to be stored
as an approximation.

Someone else mentioned a decimal data type, which works much like a
float but is designed for storing base-10 numbers.



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread allan gottlieb
On Sat, Aug 22 2015, Mike Gilbert wrote:

 On Sat, Aug 22, 2015 at 1:32 PM, Alan McKinnon alan.mckin...@gmail.com 
 wrote:
 I can tell you that equality comparisons on floats are problematic, and
 always will be due to how they are stored (double-precision floats,
 inhernetly inexact). This is not a problem per se, it's a systemic
 side effect of how our computers represent floats i.e. you can't fix
 it as there is nothing to fix

 It's not that floats are inherently inexact; it really has to do
 with trying to represent a base-10 number in a data structure designed
 to hold a base-2 number.

 If your number can be represented by some multiple of a power of 2,
 equality comparisons will work. If it cannot be, it has to be stored
 as an approximation.

I am not sure exactly what you mean.  Every number is a multiple of a
power of 2, in particular a multiple of 2^0=1.

Also

2^0 + 2^1 + 2^2 + ... 2^100 != 2^100 + 2^99 + ... + 2^1 + 2^0

on a 64-bit machine assuming left to right addition.

This example does not use floating point for that use negative exponents

2^-0 + 2^-1 + ... + 2^-100 != 2^-100 + ... + 2^-1 + 2^-0

In general for adding many positive floating point numbers, it is better
to add the small numbers first.

One more example.  Assume a DECIMAL floating point machine with two
digits of mantissa and say 20 digits of exponent.  This machine cannot
express 101 since that requires 3 digits of mantissa.  Then

100 + 1 + 1 + ... + 1 (100 1s) = 100

1 + 1 + ... + 1 + 100 (100 1s) = 200

allan



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Paul Colquhoun
On Sat, 22 Aug 2015 16:57:41 hw wrote:
 Am 22.08.2015 um 15:43 schrieb Alan McKinnon:
  On 22/08/2015 15:26, hw wrote:
  Hi,
  
  I have the following in a perl script:
 if ($a != $b) {
 
   print e: '$a', t: '$b'\n;
 
 }
  
  That will print:
  
  e: '69.99', t: '69.99'
  
  
  When I replace != with ne (if ($a ne $a) {), it doesn't print.
  
  
  Is that a bug or a feature?  And if it's a feature, what's the
  explanation?


  != does a numerical comparison. More on this below
  ne does a string comparison. When viewed as a bunch of 
characters, 69.99
  and 69.99 are identical.

  Now, your comparisons are NOT random. They are entirely 
predictable, as
  long as you know what is going on; you are running into floating 
point
  numbers. And as it turns out, computers never represent these 
things
  exactly (they are NOT integers). Even though they look identical
  on-screen, in RAM they will not be (this must be so for perl to do the
  print). Maybe they actually resolve to 69.99001 and 
69.9900. You
  see them as close-as-dammit equal, perl sees them as entirely 
different.
 
 Why can't it print the number as it is, or at least as it is compared,
 like it should?  If it would, one could see at once what the problem is.


Your print values are coming from the original variables. The numeric 
comparison does an internal conversion to two temporary variables, 
and compares those, WITHOUT affecting the original data.

This string to float conversion appears not to be deterministic, if it 
converts two identical strings into two different float values, but I don't 
know enough about the internals to comment any further.


-- 
Reverend Paul Colquhoun, ULC. http://andor.dropbear.id.au/
  Asking for technical help in newsgroups?  Read this first:
 http://catb.org/~esr/faqs/smart-questions.html#intro



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Michael Orlitzky
On 08/22/2015 09:42 AM, R0b0t1 wrote:
 https://en.wikipedia.org/wiki/Round-off_error
 https://en.wikipedia.org/wiki/Machine_epsilon
 
 Either add a tolerance (a - b = t) or compare them as strings as
 you've been doing.
 

You probably want |a - b| = t there =)

But... that can cause problems too. If your numbers are small enough,
you can wind up with infinity or NaN (not a number) and then your
comparisons will go berserk.

Floating point addition isn't even commutative:

   0.1 + 0.2 + 0.3
  0.6001
   0.1 + (0.2 + 0.3)
  0.6

Better to avoid that quagmire entirely if you can. Use fixed point
arithmetic, arbitrary precision, or even rational numbers if you can get
away with it.





Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread allan gottlieb
On Sat, Aug 22 2015, Michael Orlitzky wrote:

 On 08/22/2015 09:42 AM, R0b0t1 wrote:
 https://en.wikipedia.org/wiki/Round-off_error
 https://en.wikipedia.org/wiki/Machine_epsilon
 
 Either add a tolerance (a - b = t) or compare them as strings as
 you've been doing.
 

 You probably want |a - b| = t there =)

 But... that can cause problems too. If your numbers are small enough,
 you can wind up with infinity or NaN (not a number) and then your
 comparisons will go berserk.

 Floating point addition isn't even commutative:

0.1 + 0.2 + 0.3
   0.6001
0.1 + (0.2 + 0.3)
   0.6

That demonstrates non-associativity.  I believe floating point is
commutative: a+b = b+a

 Better to avoid that quagmire entirely if you can. Use fixed point
 arithmetic, arbitrary precision, or even rational numbers if you can get
 away with it.

Agreed.
allan



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Alan McKinnon
On 22/08/2015 16:57, hw wrote:
 
 
 Am 22.08.2015 um 15:43 schrieb Alan McKinnon:
 On 22/08/2015 15:26, hw wrote:

 Hi,

 I have the following in a perl script:


if ($a != $b) {
  print e: '$a', t: '$b'\n;
}


 That will print:

 e: '69.99', t: '69.99'


 When I replace != with ne (if ($a ne $a) {), it doesn't print.


 Is that a bug or a feature?  And if it's a feature, what's the
 explanation?

 And how do you deal with comparisions of variables when you get randomly
 either correct results or wrong ones?  It's randomly because this
 statement checks multiple values in the script, and 69.99 is the only
 number showing up yet which isn't numerically equal to itself (but equal
 to itself when compared as strings).



 Computer languages have a much more exact idea of what equality means
 than you do. In your head (because you are human, not silicon) you are
 completely comfortable with taking 69.99 and treat8ing it as a string,
 or a number, or a mostly-rounded-off floating point number.

 The computer does not do it like that. To a computer, the same must be
 exactly the same. Two things a little bit different are completely
 different (or not equal). And perl has two different operators for
 (in)equality:

 != does a numerical comparison. More on this below
 ne does a string comparison. When viewed as a bunch of characters, 69.99
 and 69.99 are identical.
 
 When the value is numerically not 69.99 but something like 69.99001,
 then printing the value should print 69.99001 rather than 69.99.
 
 perl -e 'print 1/3 . \n;' prints 0.333
 
 perl -e 'printf(%34.32f\n, 1/3);' prints
 0.1482961625624739
 
 perl -e 'print (((1/3 == 0.333) ? equal : not equal) .
 \n);' prints not equal
 
 perl -e 'print (((1/3 == 0.0.1482961625624739) ? equal
 : not equal) . \n);' prints Integer overflow in decimal number at
 -e line 1. a couple times
 
 This is random, may it be predictable or not, and what's the integer here?
 
 Now, your comparisons are NOT random. They are entirely predictable, as
 long as you know what is going on; you are running into floating point
 numbers. And as it turns out, computers never represent these things
 exactly (they are NOT integers). Even though they look identical
 on-screen, in RAM they will not be (this must be so for perl to do the
 print). Maybe they actually resolve to 69.99001 and 69.9900. You
 see them as close-as-dammit equal, perl sees them as entirely different.
 
 Why can't it print the number as it is, or at least as it is compared,
 like it should?  If it would, one could see at once what the problem is.

I can't see your code and I don't know how you get values assigned to
those variables so I can't really give you an answer.

I can tell you that equality comparisons on floats are problematic, and
always will be due to how they are stored (double-precision floats,
inhernetly inexact). This is not a problem per se, it's a systemic
side effect of how our computers represent floats i.e. you can't fix
it as there is nothing to fix

Rob0t1's suggestion was the best, I'd forgotten that neat trick:

replace

if ($a != $b)

with

if ($a - $b = $t)
where $t is an acceptable tolerance (0.001 in your case should be OK)


 
 This is such as huge IT problem that many solutions have been proposed.
 You get classes like BigFloat that represent a floating point as an
 integer so that equality works, you can round the floats off before
 comparing them, or just make the things integers.

 The last one is nice: don't represent money as dollars and cents,
 represent it as cents or decicents and only divide by 100 (or 1000) when
 you finally get to display it.
 
 That would add quite a lot of complexity, and the problem should either
 be handled transparently, or the value should be printed as the
 software/computer sees it.  It is a recipe for disaster when you tell
 your computer to print something but it prints something else instead.
 
 So how to fix your problem: you are doing what you shouldn't do - trying
 equality on floats. Turn them into integers, or round them off, or use
 =/= instead of !=
 
 '=/=' is not an operator in perl?

Oops. Mail-client mangling. The line started with  and the slash is or

It should read = or =




-- 
Alan McKinnon
alan.mckin...@gmail.com




Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Alan McKinnon
On 22/08/2015 17:38, Alexander Kapshuk wrote:
 On Sat, Aug 22, 2015 at 4:26 PM, hw h...@gartencenter-vaehning.de wrote:

 Hi,

 I have the following in a perl script:


   if ($a != $b) {
 print e: '$a', t: '$b'\n;
   }


 That will print:

 e: '69.99', t: '69.99'


 When I replace != with ne (if ($a ne $a) {), it doesn't print.


 Is that a bug or a feature?  And if it's a feature, what's the explanation?

 And how do you deal with comparisions of variables when you get randomly
 either correct results or wrong ones?  It's randomly because this statement
 checks multiple values in the script, and 69.99 is the only number showing
 up yet which isn't numerically equal to itself (but equal to itself when
 compared as strings).

 
 Perl Cookbook, 2nd edition, suggests these two approaches to comparing
 floats for equality.
 (1). Use sprintf to format the numbers to a certain number of decimal
 places, then compare the resulting strings.
 (2). Alternatively, store the numbers as integers by assuming the decimal 
 place.


A good way to demonstrate just how problematic floats can be is to point
out that floats are banned in the linux kernel for exactly this reason.
Integers only.


-- 
Alan McKinnon
alan.mckin...@gmail.com




Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Michael Orlitzky
On 08/22/2015 01:27 PM, allan gottlieb wrote:

 Floating point addition isn't even commutative:

0.1 + 0.2 + 0.3
   0.6001
0.1 + (0.2 + 0.3)
   0.6
 
 That demonstrates non-associativity.  I believe floating point is
 commutative: a+b = b+a
 

Derp, thanks, you're right =)

...but it's not commutative either:

   nan = float('nan')
   nan + 1 == 1 + nan
  False

I'm cheating a bit there, the real problem is:

   nan == nan
  False




Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Alexander Kapshuk
On Sat, Aug 22, 2015 at 4:26 PM, hw h...@gartencenter-vaehning.de wrote:

 Hi,

 I have the following in a perl script:


   if ($a != $b) {
 print e: '$a', t: '$b'\n;
   }


 That will print:

 e: '69.99', t: '69.99'


 When I replace != with ne (if ($a ne $a) {), it doesn't print.


 Is that a bug or a feature?  And if it's a feature, what's the explanation?

 And how do you deal with comparisions of variables when you get randomly
 either correct results or wrong ones?  It's randomly because this statement
 checks multiple values in the script, and 69.99 is the only number showing
 up yet which isn't numerically equal to itself (but equal to itself when
 compared as strings).


Perl Cookbook, 2nd edition, suggests these two approaches to comparing
floats for equality.
(1). Use sprintf to format the numbers to a certain number of decimal
places, then compare the resulting strings.
(2). Alternatively, store the numbers as integers by assuming the decimal place.



Re: [gentoo-user] 69.99 != 69.99

2015-08-22 Thread Franz Fellner
On Sat, 22 Aug 2015 16:57:41 +0200, hw h...@gartencenter-vaehning.de wrote:
 
 
 Am 22.08.2015 um 15:43 schrieb Alan McKinnon:
  On 22/08/2015 15:26, hw wrote:
 
  Hi,
 
  I have the following in a perl script:
 
 
 if ($a != $b) {
   print e: '$a', t: '$b'\n;
 }
 
 
  That will print:
 
  e: '69.99', t: '69.99'
 
 
  When I replace != with ne (if ($a ne $a) {), it doesn't print.
 
 
  Is that a bug or a feature?  And if it's a feature, what's the explanation?
 
  And how do you deal with comparisions of variables when you get randomly
  either correct results or wrong ones?  It's randomly because this
  statement checks multiple values in the script, and 69.99 is the only
  number showing up yet which isn't numerically equal to itself (but equal
  to itself when compared as strings).
 
 
 
  Computer languages have a much more exact idea of what equality means
  than you do. In your head (because you are human, not silicon) you are
  completely comfortable with taking 69.99 and treat8ing it as a string,
  or a number, or a mostly-rounded-off floating point number.
 
  The computer does not do it like that. To a computer, the same must be
  exactly the same. Two things a little bit different are completely
  different (or not equal). And perl has two different operators for
  (in)equality:
 
  != does a numerical comparison. More on this below
  ne does a string comparison. When viewed as a bunch of characters, 69.99
  and 69.99 are identical.
 
 When the value is numerically not 69.99 but something like 69.99001, 
 then printing the value should print 69.99001 rather than 69.99.

To take your perl statement:
perl -e 'printf(%34.32f\n, 23.33*3)'
69.98488409230252727866

It doesnt print that strange value because it rounds it to something
more readable, as the value is known to be not as precise.

 
 perl -e 'print 1/3 . \n;' prints 0.333
 
 perl -e 'printf(%34.32f\n, 1/3);' prints 
 0.1482961625624739
 
 perl -e 'print (((1/3 == 0.333) ? equal : not equal) . 
 \n);' prints not equal
 
 perl -e 'print (((1/3 == 0.0.1482961625624739) ? equal 
 : not equal) . \n);' prints Integer overflow in decimal number at 
 -e line 1. a couple times

typo ;)
1/3 == 0.0.333[...]
Here it prints equal.

 
 This is random, may it be predictable or not, and what's the integer here?
 
  Now, your comparisons are NOT random. They are entirely predictable, as
  long as you know what is going on; you are running into floating point
  numbers. And as it turns out, computers never represent these things
  exactly (they are NOT integers). Even though they look identical
  on-screen, in RAM they will not be (this must be so for perl to do the
  print). Maybe they actually resolve to 69.99001 and 69.9900. You
  see them as close-as-dammit equal, perl sees them as entirely different.
 
 Why can't it print the number as it is, or at least as it is compared, 
 like it should?  If it would, one could see at once what the problem is.
 
  This is such as huge IT problem that many solutions have been proposed.
  You get classes like BigFloat that represent a floating point as an
  integer so that equality works, you can round the floats off before
  comparing them, or just make the things integers.
 
  The last one is nice: don't represent money as dollars and cents,
  represent it as cents or decicents and only divide by 100 (or 1000) when
  you finally get to display it.
 
 That would add quite a lot of complexity, and the problem should either 
 be handled transparently, or the value should be printed as the 
 software/computer sees it.  It is a recipe for disaster when you tell 
 your computer to print something but it prints something else instead.
 
  So how to fix your problem: you are doing what you shouldn't do - trying
  equality on floats. Turn them into integers, or round them off, or use
  =/= instead of !=
 
 '=/=' is not an operator in perl?