# Compare, two identical numbers are not the same?!

Discussion in 'Perl Misc' started by Justin C, Jun 29, 2009.

1. ### Justin CGuest

This one is really confusing me. I have a comparison:

\$totalIndividualWeights != \$param{weight}

and when they're both 42.6 (probably other numbers too, but this is the
problem someone has, and has come to me with) Perl says they're not the
same:

if (\$totalIndividualWeights != \$param{weight}){
print "Weight does not add up to total weight given on the first form.\\$totalIndividualWeights = \$totalIndividualWeights \n \\$param{weight} = \$param{weight}";
}

The print statement says both weights are 42.6. \$param{weight} was
input by the user, \$totalIndividualWeights is reached by adding several
user inputs: 2.86, 9.94, 9.98, 9.88, 9.94

Does perl have a problem with empty decimal places? What I mean is, the
inputs are to two decimals, but the result is only using one, is perl
thinking "42.60" and not matching 42.6?

Justin.

--
Justin C, by the sea.

Justin C, Jun 29, 2009

2. ### Jürgen ExnerGuest

Justin C <> wrote:
>
>This one is really confusing me. I have a comparison:
>
>\$totalIndividualWeights != \$param{weight}
>
>and when they're both 42.6 (probably other numbers too, but this is the
>problem someone has, and has come to me with) Perl says they're not the
>same:

You forgot the first commandment of computer numerics:

Thou shalt not use equality for floating point numbers!

See 'perldoc -q 9999' for further details. Although those seem to be
unrelated questions/issues in fact they have the same underlying reason
which applies to virtually all programming languages.

>The print statement says both weights are 42.6

Try printing them with 20 digits:
printf("%.20f", \$totalIndividualWeights)
You may be surprised.

jue

Jürgen Exner, Jun 29, 2009

3. ### Jürgen ExnerGuest

Glenn Jackman <> wrote:
>At 2009-06-29 12:24PM, "Justin C" wrote:
>> The print statement says both weights are 42.6. \$param{weight} was
>> input by the user, \$totalIndividualWeights is reached by adding several
>> user inputs: 2.86, 9.94, 9.98, 9.88, 9.94

>
>Are you comparing "42.6\n" to a number that's close to 42.6?

If that were the case then he should have gotten a warning about
non-numerical value used in numerical comparison. At least if he had
used warnings.

Technically it doesn't matter. He is using numerical compare "=", thus
Perl uses the arguments in numerical context and therefore automatically
converts the string "42.6\n" into the numerical floating point value
42.6 resp. something very close to it.

jue

Jürgen Exner, Jun 30, 2009
4. ### Jürgen ExnerGuest

>Jürgen Exner <> wrote:
>> Glenn Jackman <> wrote:
>>>At 2009-06-29 12:24PM, "Justin C" wrote:
>>>> The print statement says both weights are 42.6. \$param{weight} was
>>>> input by the user, \$totalIndividualWeights is reached by adding several
>>>> user inputs: 2.86, 9.94, 9.98, 9.88, 9.94
>>>

>
>> If that were the case then he should have gotten a warning about
>> non-numerical value used in numerical comparison. At least if he had
>> used warnings.

>
>No, there is no warning for trailing whitespace.

I stand corrected.

jue

Jürgen Exner, Jun 30, 2009
5. ### Justin CGuest

On 2009-06-29, Jürgen Exner <> wrote:
> Justin C <> wrote:
>>
>>This one is really confusing me. I have a comparison:
>>
>>\$totalIndividualWeights != \$param{weight}
>>
>>and when they're both 42.6 (probably other numbers too, but this is the
>>problem someone has, and has come to me with) Perl says they're not the
>>same:

>
> You forgot the first commandment of computer numerics:
>
> Thou shalt not use equality for floating point numbers!

Being self-taught this had passed me by (I'm not qualified to teach
Perl you see, that's why my education was lacking this nugget - among
others).

OK. I can be certain that a user will never put in a number using more
than two decimal places - if they do I can reject it. Would I be better
off multiplying the input data by 100 and working in integars only? Then
dividing by 100 only when I need the "real" number? It sure looks like
it would make life easier.

On the other hand, the sprintf trick works. Maybe I should just try and
remember not to compare floats - that's obviously the best solution
because it'll save me asking again in the future.

Maybe, when I write my end of term report for myself, I should mention
this, maybe I'll remember it when I read what my teacher says about me.

> See 'perldoc -q 9999' for further details. Although those seem to be
> unrelated questions/issues in fact they have the same underlying reason
> which applies to virtually all programming languages.
>
>>The print statement says both weights are 42.6

>
> Try printing them with 20 digits:
> printf("%.20f", \$totalIndividualWeights)
> You may be surprised.

Justin.

--
Justin C, by the sea.

Justin C, Jun 30, 2009
6. ### ccc31807Guest

On Jun 30, 10:17 am, Justin C <> wrote:
> OK. I can be certain that a user will never put in a number using more
> than two decimal places - if they do I can reject it. Would I be better
> off multiplying the input data by 100 and working in integars only?

Test that the absolute value of the difference between the two is less
than, say, 0.001, or whatever your tolerance is. You can create a user
defined function that returns true or false for your convenience, like

if (within_tolerance( val1, val2)) #if true
{ then_do_something(); }
else #if false
{ do_something_else(); }

CC

ccc31807, Jun 30, 2009
7. ### Jürgen ExnerGuest

Justin C <> wrote:
>On 2009-06-29, Jürgen Exner <> wrote:
>> You forgot the first commandment of computer numerics:
>>
>> Thou shalt not use equality for floating point numbers!

>
>OK. I can be certain that a user will never put in a number using more
>than two decimal places - if they do I can reject it. Would I be better
>off multiplying the input data by 100 and working in integars only?

That would be one common approach to avoid any inaccuracies caused by
floating point arithmetic.

>Then
>dividing by 100 only when I need the "real" number? It sure looks like
>it would make life easier.

Think of it as doing all calculations in cent instead of in dollar or
euro and only convert them into a 'human-friendly" format when printing
If this works for your application then it's the best posible solution.

However, computer numerics are tricky, there is a reason why it is a
subject matter at university, and even that method is not fool-proof.

Example: when calculating interest on a long list of accounts, even if
you manage them internally in cent, you may get a different result when
adding up all the interest paid to each account compared to calculating
the sum of all accounts and then the interest on the lump sum. Those
rounding errors are what's driving accountants and bankers nuts because
it takes forever to find out where and why those 3 cents went missing in
action while the missing million will be spotted immediately.

>On the other hand, the sprintf trick works. Maybe I should just try and
>remember not to compare floats -

It is ok to compare floats for smaller/larger. But instead of checking
for equal you must check if the difference between the two numbers is
smaller than some tiny number. How large that tiny number is depends on
your application area, but it will never be 100% accurate.

jue

Jürgen Exner, Jun 30, 2009
8. ### Justin CGuest

On 2009-06-30, Jürgen Exner <> wrote:
> Justin C <> wrote:
>>On 2009-06-29, Jürgen Exner <> wrote:
>>> You forgot the first commandment of computer numerics:
>>>
>>> Thou shalt not use equality for floating point numbers!

>>
>>OK. I can be certain that a user will never put in a number using more
>>than two decimal places - if they do I can reject it. Would I be better
>>off multiplying the input data by 100 and working in integars only?

>
> That would be one common approach to avoid any inaccuracies caused by
> floating point arithmetic.

I'll try and remember this for another time I might need it.

>>On the other hand, the sprintf trick works. Maybe I should just try and
>>remember not to compare floats -

>
> It is ok to compare floats for smaller/larger. But instead of checking
> for equal you must check if the difference between the two numbers is
> smaller than some tiny number. How large that tiny number is depends on
> your application area, but it will never be 100% accurate.

Thank you, Jurgen and CC. I'm doing a straight compare of two sprintf
'numbers', but I quite like the idea of testing the difference - a
tollerance as CC put it. I might re-write the code for proof of concept,
and "doing it" actually gets it into my head better than reading it.

Justin.

--
Justin C, by the sea.

Justin C, Jul 2, 2009
9. ### Guest

On Thu, 02 Jul 2009 22:48:58 -0000, Justin C <> wrote:

>On 2009-06-30, Jürgen Exner <> wrote:
>> Justin C <> wrote:
>>>On 2009-06-29, Jürgen Exner <> wrote:
>>>> You forgot the first commandment of computer numerics:
>>>>
>>>> Thou shalt not use equality for floating point numbers!
>>>
>>>OK. I can be certain that a user will never put in a number using more
>>>than two decimal places - if they do I can reject it. Would I be better
>>>off multiplying the input data by 100 and working in integars only?

>>
>> That would be one common approach to avoid any inaccuracies caused by
>> floating point arithmetic.

>
>I'll try and remember this for another time I might need it.
>
>
>>>On the other hand, the sprintf trick works. Maybe I should just try and
>>>remember not to compare floats -

>>
>> It is ok to compare floats for smaller/larger. But instead of checking
>> for equal you must check if the difference between the two numbers is
>> smaller than some tiny number. How large that tiny number is depends on
>> your application area, but it will never be 100% accurate.

>
>Thank you, Jurgen and CC. I'm doing a straight compare of two sprintf
>'numbers', but I quite like the idea of testing the difference - a
>tollerance as CC put it. I might re-write the code for proof of concept,
>and "doing it" actually gets it into my head better than reading it.
>
> Justin.

The ballpark for comparisons are C functions ceil/floor (posix in perl).
Never can you compare doubles for equality, and never can you even see a
print of thier actual float value.

There is only one need for true comparisons, the is the case of
Numerical Methods absolute "difference" being less/greater than some
value. Or in the case of rounding is needed (ala the Pentium 60 bug
where zero is less than some absolute value of some really small fraction
of 1).

-sln

, Jul 4, 2009