Precision in languages

I’ve talked about precision in previous posts quite a while ago. I had seen some interesting posts about Javascript, which suggested that it was not immune to the same issues … if anything it was as problematic as most other languages, and maybe had a little less “guarding” the programmer against potential failure modes.

This is not a terrible problem, I just found it amusing. Understand that I actually like Javascript. It does remind me in some ways of Perl and other tools I’ve used for writing code. Sadly it doesn’t seem to have Perl’s power for working with strings, parsing, etc. yet. Or mebbe I just don’t have the right libraries in mind. Doesn’t matter, v8 compiles it down to bloody fast code. Sadly, Perl6’s static compilation capabilities are lacking, and it is built upon the Parrot VM, so no matter how fast you can make Parrot, you still have a VM in the way, and you aren’t as close to bare silicon as you might like.

Several tweets pointed to interesting similar issues in other languages. Python, Lua, and Java.

So I decided to try Perl as well with the Python example.


my $a = 10000000000000000;
my $b = 10000000000000001;

printf "a = %i\n",$a;
printf "b = %i\n",$b;

printf " a == b is %s\n",( $a == $b ? "true" : "false");

my $c = 10000000000000000.0;
my $d = 10000000000000001.0;

printf "c = %s\n",$c;
printf "d = %s\n",$d;

printf " c == d is %s\n",( $c == $d ? "true" : "false");

Now try it

landman@pegasus:/tmp$ perl 
a = 10000000000000000
b = 10000000000000001
 a == b is false
c = 1e+16
d = 1e+16
 c == d is true

Yeah. Same problem in Perl. How hard is it to work around (e.g. hide the real problem)?

Not hard at all. Use multiprecision libs by default

landman@pegasus:/tmp$ perl -Mbignum 
a = 10000000000000000
b = 10000000000000001
 a == b is false
c = 10000000000000000
d = 10000000000000001
 c == d is false

Ignore the liberties the float to string conversion took in the second set of printf’s.

Yeah, this is an issue. Using multiprecision everywhere is slow, and could lead to some surprising memory usage for computational code. Its fairly obvious that the example was somewhat contrived as well … as to the relative precision of the numbers, the second comparison being true shouldn’t be a problem.

No, thats not what I found interesting. It was the missing integers example.

Ok. I have no problem with FP format, and occasional “surprises” around that. The thing I found intriguing was an integer “resolution” problem in javascript.

Their code

var n = 1000;
var from = 10000000000000000;
var to = from + n;
var i = from;
var missing = [];
while (i < to) { var incr = 1; while (i === i+incr) { missing.push(i+" + "+incr); incr ++; } i += incr; } console.log(missing); console.log(missing.length+" values are missing."); // logs: 250 values are missing.

I just ran this through node.js on my laptop, and sure enough, it skips 4 integers. This looks like a "resolution" problem of some sort ... for integers. But as they note, Javascript really doesn't do integers. Numbers are all floats.

Perl goes somewhat deeper, and lets you specify if you want to force using integers in your basic block (not really typed variables, but a coercion of sorts). Lets not use that and simply convert the Javascript to Perl and run it.

my $n = 1000;
my $from = 10000000000000000;
my $to = $from + $n;
my $i = $from;
my @missing ;
while ($i < $to) { $incr = 1; while ($i == $i+$incr) { push @missing,(sprintf "%i + %i",$i,$incr); $incr++; } $i += $incr; }map {printf "%s\n",$_} @missing; printf "N(missing) = %i\n",$#missing+1;

I slightly altered the last line to print "N(missing)" rather than "values are missing". Same thing, and somewhat irrelevant.

Node.js does indeed give me the results that the poster indicated. Node.js, and Javascript use floating point by default for numbers.

So does Perl.

landman@pegasus:/tmp$ perl 
N(missing) = 0

Not quite sure we can draw significant conclusion from this, other than a serious "hmmmmm".

But this gets to one of the things that people using strongly typed languages like ... when you specify an integer, you get ... an ... integer.

There's a positive to this, and a negative to this. The positive is, you get exactly what you ask for. The negative is, you have to (usually) explicitly cast it to something else if you want to "convert" it.

Likely, the issue in Javascript has to do with this conversion process losing a bit or two. It should be fixable.

But all languages could bite you hard if you make an assumption about types and precision which is unwarranted. So if you are coming from a strongly typed language, starting to run in Javascript, or Perl, or others, yes, you are going to likely encounter some issues.

Viewed 52300 times by 5434 viewers