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  
> 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 Mike Gilbert
On Sat, Aug 22, 2015 at 1:32 PM, Alan McKinnon  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 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 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 Alan McKinnon
On 22/08/2015 17:38, Alexander Kapshuk wrote:
> On Sat, Aug 22, 2015 at 4:26 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).
>>
> 
> 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 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 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 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 Alexander Kapshuk
On Sat, Aug 22, 2015 at 4:26 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).
>

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  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?
> 



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 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 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.