Hi,
To capture some critical examples of float to string
conversion I went with this kind of little excess
precision and had this float to string conversion:
return shape_number(num.toPrecision(17));
Which gives this unfortunate result, still in release
1.2.1 of Dogelog Player for JavaScript seen:
?- between(1,10,N), X is (20+N)/10, write(X), nl, fail; true. 2.1000000000000001
2.2000000000000002
2.2999999999999998
2.3999999999999999
2.5
2.6000000000000001
2.7000000000000002
2.7999999999999998
2.8999999999999999
3.0
One work around is to check whether precision 16 would
also work. Like this code here:
let res = num.toPrecision(16);
if (Number(res) === num) {
return shape_number(res);
} else {
return shape_number(num.toPrecision(17));
}
The results are much more eye friendly:
?- between(1,10,N), X is (20+N)/10, write(X), nl, fail; true.
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
3.0
true.
Can we accept this solution? Will it slow down printing?
Further test cases are:
?- X is 370370367037037036703703703670 / 123456789012345678901234567890.
X = 3.0000000000000004.
?- X is 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1.
X = 0.7999999999999999.
The first test case doesn't work in SWI-Prolog
since recently it has improve its realization of
(/)/2 arithemetic function. While in most Prolog
systems we should have the above result, since
neither the division equals 3.0 nor the sum equals
0.8 when we use floating point numbers, and
when we convert first to floating point number
before doing the division. The adaptive algorithm
is more expensive than just calling num.toPrecision(17).
It will in mimimum call num.toPrecision(16) and do
the back conversion, i.e. Number(res). So unparsing
has a parsing cost. And for critical numbers, it
has a second unparsing via num.toPrecision(17) cost.
But I guess we can accept this little slow down.
Here are two test cases for memory
management of a Prolog system:
/* bomb */
app([], X, X).
app([X|Y], Z, [X|T]) :- app(Y, Z, T).
garbage(0, [0]) :- !.
garbage(N, L) :- M is N-1, garbage(M, R), app(R, R, L).
foo :- garbage(12,_), foo.
/* xbetween */
xbetween1(L, _, L).
xbetween1(L, U, N) :- L < U, M is L+1, xbetween1(M, U, N).
They test possibly something different. xbetween does
not produce a lot of objects during tail recursion,
it only decrements one integer. The xbetween example
might be ok, wherea the bomb example might be neverthelesss
not ok, especially since unlike in the xbetween example,
the bomb example has also an "intermediate" variables.
The "intermediate" variable is "_":
foo :- garbage(12,_), foo.
The xbetween example has no such variable. All
variables in the xbetween example are either in
the head or in the tail recursive call, making
it a more trivial example than the bomb example.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 491 |
Nodes: | 16 (2 / 14) |
Uptime: | 146:50:45 |
Calls: | 9,694 |
Calls today: | 4 |
Files: | 13,732 |
Messages: | 6,178,670 |