Perl: the Markov chain saw PerlMonks

### Okay! What!?!?!?

 on Apr 23, 2014 at 00:36 UTC Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

So value 1 is 14.4 and value 2 is 14.4, why is this evaluating to false?? Maybe I'm crazy.
```my \$value1 = 14.4;
print "value1 = \$value1\n";

my \$value2 = 10 + 14.4 - 10;
print "value2 = \$value2\n";

if ( \$value1 == \$value2 ) {
print "value 1 equals value 2\n";
} else {
print "value 1 does not equal value2\n";
}

Replies are listed 'Best First'.
Re: Okay! What!?!?!?
by davido (Archbishop) on Apr 23, 2014 at 06:26 UTC

On my system (Perl5.18.2):

```#!/usr/bin/env perl
printf "%.49f\n", 14.4;
printf "%.49f\n", 10 + 14.4 - 10;

...outputs...

```14.4000000000000003552713678800500929355621337890625
14.3999999999999985789145284797996282577514648437500

And (GNU C++).....

```#include <iostream>
#include <iomanip>

using namespace std;

int main () {
cout << setprecision(51) << endl;
cout << 14.4 << endl;
cout << 10 + 14.4 - 10 << endl;
return 0;
}

...outputs...

```14.4000000000000003552713678800500929355621337890625
14.39999999999999857891452847979962825775146484375

And (GNU C)

```#include <stdio.h>

int main (void) {
printf("%.49f\n", 14.4);
printf("%.49f\n", 10.0 + 14.4 - 10.0);
return 0;
}

...produces this output:

```14.4000000000000003552713678800500929355621337890625
14.3999999999999985789145284797996282577514648437500

This is because the decimal value 14.4 cannot be perfectly represented as a fraction in the form of n/(2^m), and therefore has a non-terminating binary expansion.

The code I've shown above is first Perl, and second C++, and the third, C, just to illustrate that this is not a problem specific to just Perl. Here's yet another link that attempts to explain it: Re: shocking imprecision

Update: Here's a Lisp (Racket, a Scheme derivative) example as well:

```#!/usr/bin/env racket
#lang racket

(displayln (~a 14.4 #:width 15 #:pad-string "0"))
(displayln (~a (- (+ 10 14.4) 10) #:width 15 #:pad-string "0"))
(= 14.4 (- (+ 10 14.4) 10))

...outputs...

```14.400000000000
14.399999999999
#f

(The "#f" means "false"; 14.40 doesn't equal 14.399...)

JavaScript (minimal example):

```alert(10+14.4-10);

The pop-up displays: "14.399999999999999"

Python:

```>>> print "%.49f"%14.4
14.4000000000000003552713678800500929355621337890625
>>> print "%.49f"%(10+14.4-10)
14.3999999999999985789145284797996282577514648437500

Ruby:

```\$ ruby -e 'printf "%.49f\n%.49f\n",14.4, 10+14.4-10'
14.4000000000000003552713678800500929355621337890625
14.3999999999999985789145284797996282577514648437500

SQL (sqlite):

```sqlite> select 14.4 - (10 + 14.4 - 10);
1.77635683940025e-15

Couldn't remember enough Pascal. "Go" must optimize away the math, because while it does produce an imprecise representation of 14.4, it produces the same imprecise representation for both 14.4, and 10+14.4-10. (GO):

```package main

import "fmt"

func main() {
fmt.Printf("%.49f\n",14.4)
fmt.Printf("%.49f\n", 10+14.4-10)
}
---------
14.4000000000000003552713678800500929355621337890625
14.4000000000000003552713678800500929355621337890625

Program exited.

Update: I left out Java because node lengths at PerlMonks are restricted to 64k (j/k -- I just don't know any Java)

Dave

It's been about 15 years since I've written any Pascal, but here you go...

```program floating;

var
A, B :real;

begin
A := 14.4e0;
B := 10.0e0 + 14.4e0 - 10.0e0;

writeln( A );
writeln( B );

if A = B then
writeln('they are equal')
else
writeln('they differ');
end.

Compiled using Free Pascal Compiler 2.6.2-5 (i386), I get the following output:

``` 1.44000000000000E+001
1.44000000000000E+001
they are equal

I don't know if FPC is especially smart at optimizing the mathematical expressions, or especially smart at DWIM output and comparisons on floating point numbers. But it's being smart somehow.

use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

This could be explained by the compiler knowing to perform the constant folding in an order that reduces the risk of loss of precision.

So do the addition and subtraction as separate steps.

- tye

There must be some behind the scenes DWIMery, because according to the documentation, FreePascal's "real" type maps directly to a standard IEEE 754 "double" on most architectures, and as such, should suffer from the same shortcomings of representing floating point numbers in base 2.

Dave

Go suffers from this problem too. It uses an arbitrary number representation for constants only, which are computed at compile-time.

For example, the following code:

```package main

import "fmt"

func main() {

x := 14.4;
y := 10.0;

fmt.Printf("%.49f\n", x)
fmt.Printf("%.49f\n", x+y-y)
}
Outputs:
```14.4000000000000003552713678800500929355621337890625
14.3999999999999985789145284797996282577514648437500

"I just don't know any Java"

Me too (not really). So a i used a GUI:

Update: fixed typo.

```
package Perlmonks;

public class Testomato {

public static void main(String[] args) {
System.out.printf("%.49f\n",14.4);
System.out.printf("%.49f\n", 10+14.4-10);
}

}

I get:

```14,4000000000000000000000000000000000000000000000000
14,3999999999999990000000000000000000000000000000000

Regards, Karl

«The Crux of the Biscuit is the Apostrophe»

Re: Okay! What!?!?!?
by soonix (Monsignor) on Apr 23, 2014 at 07:09 UTC
Re: Okay! What!?!?!?
by Anonymous Monk on Apr 23, 2014 at 02:14 UTC
Re: Okay! What!?!?!?
by LanX (Bishop) on Apr 23, 2014 at 00:47 UTC
See eq and Equality Operators

Cheers Rolf

( addicted to the Perl Programming Language)

I understand that 'eq' is better, but this question came from a horribly designed test and the '==' operator has to be used.

I think they should be equal but the code isn't coming out as equal?

So for this test ( actual job test question ), what's the proper answer?

It's (again) a floating point problem.

```  DB<149> \$a=14.4
=> "14.4"

DB<150> \$b=10+\$a-10
=> "14.4"

DB<151> \$a-\$b
=> "1.77635683940025e-15"

The mantissa does loose some digits at the end after adding 10 and substracting doesn't bring them back.

A proper test is either to stay integer from the beginning till the end or to calculate the difference and to compare against a threshold (trickier).

Please note how 14.5 doesn't have this problem since 1/2 is a power of 2 (i.e. only 0s are lost when shifting the mantissa)

##### update
see Re: eq vs == and Humans have too many fingers for more details

Cheers Rolf

( addicted to the Perl Programming Language)

Re: Okay! What!?!?!?
by sundialsvc4 (Abbot) on Apr 23, 2014 at 02:09 UTC

I don’t rightly know what the (stringwise ...) eq operator would do in this obviously-numeric case, and I would not want to find out, even if someone proclaimed that it “worked.”

Clearly, this is just a prototypical example of why you can never (in any programming language other than COBOL) test a fractional number for “exact equality.”   Even if the binary value rounds to exactly the same sequence of printed digits, and thus “to our human eyes” is ‘the same number,’ it is the binary values that are being compared by the computer, and these are almost certain to be “unequal.”

Clearly, this is just a prototypical example of why you can never (in any programming language other than COBOL) test a fractional number for “exact equality.”

Only if by "fractional number" you actually mean floating-point number. It works fine with actual fractional numbers:

```\$ perl6 -e 'say 10 + 14.4 - 10 == 14.4'
True

(Perl 6 stores those as actual fractions, and does exact math with them; you only get floating points if the fractions overflow, or if you request them with the scientific notation 14.4e0).

He said "programming language," not multi-decade performance art. COBOL has users.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://1083247]
Approved by awohld
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2018-05-25 17:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
World peace can best be achieved by:

Results (188 votes). Check out past polls.

Notices?