Hi all !

I think you show below that the floating point standard is not the cause of the faulty result, but that comparison tolerance is. JWithATwist uses the same IEEE-754 floating point numbers and as we can see does not give this faulty result.

From: http://code.jsoftware.com/wiki/Essays/Tolerant_Comparison#Tolerant_Floor_and_Ceiling

"The algorithm used by J (see tfloor and tceiling below) starts with the integer nearest to a, rounding up if 0.5 (=!.0) 1|a. Then, to obtain the floor of a, we subtract one if the result is tolerantly greater than a. Since the rounded number was within 0.5 of a, the smallest this number can be is a - 0.5. Similarly, for the ceiling, we add one if it is tolerantly less than a."

9!:19 ''

|rank error


From: http://code.jsoftware.com/wiki/Essays/Tolerant_Comparison#Tolerant_Floor_and_Ceiling


"The tolerance is normally 2^_44"


2^_44

5.68434e_14


(2^_44 )*10^14

5.68434


To do Floor, J takes 100000000000000.500, rounds it to 100000000000001.000. This is not tolerantly greater than 100000000000000.500, since CT is 5.7, 1 is then not subtracted, as far as I can understand. It seems very peculiar.


What I think this shows is that we also have to consider comparison tolerance in our discussion concerning automatic type conversions. When the programmer can not control the types it is hard for him to control the effects of comparison tolerance in calculations?

/Erling


On 2016-08-22 14:43, Raul Miller wrote:
This happens because J is using 64 bit IEEE-754 floating point numbers.

See https://en.wikipedia.org/wiki/IEEE_floating_point for an overview.

This loss of precision is specified as a part of that standard.

More specifically, these numbers can be approximated as the expression:
    s*m+2^e

where
    s is _1 or 1
    m is in the range 0 .. 2^53
    e is in the range _1022 .. 1023

This standard is used because support for these numbers is baked into
the hardware. (Literally millions of transistors have been laid down
in your computer to implement these numbers.)

Even more specifically:

    fc=:3!:5
    ieee754=:3 :'(1 j.;1{.&.>~-1 11 52)#''01''{~,}.#:255,a.i.|.2 fc y'

    ieee754 0
0 00000000000 0000000000000000000000000000000000000000000000000000
    ieee754 1
0 01111111111 0000000000000000000000000000000000000000000000000000
    ieee754 2
0 10000000000 0000000000000000000000000000000000000000000000000000
    ieee754 3
0 10000000000 1000000000000000000000000000000000000000000000000000
    ieee754 5
0 10000000001 0100000000000000000000000000000000000000000000000000
    ieee754 7
0 10000000001 1100000000000000000000000000000000000000000000000000

Note that the very first bit of m is omitted from the representation
(because except for zero, every number has that bit and it is not
necessary to state it - and zero can be recognized by an all zero bit
pattern).

Also note that e is specified using an offset.

    #. 0 1 1 1 1 1 1 1 1 1 1
1023

Subtract 1023 from the integer represented by the bit pattern to get
the intended value of e.

Finally, note that m is interpreted as a binary fraction in the range
0 .. 1 and with that implied leading 1, the denominator has an implied
value of

    #.1,52#0
4503599627370496

So we can extract the implied values from the floating point representation:

s_e_m=: 3 :0
   b=. , }. #: 255, a.i. |. 2 fc y
   s=: _1^ {. b
   e=: _1023+ #. 11{. }. b
   m=: (#. 1, 12}. b) % 2^52x
   s,e,m
)

    s_e_m 1
1   0 1.00000000000000000
    s_e_m 2
1   1 1.00000000000000000
    s_e_m 3
1   1 1.50000000000000000

With that out of the way, we are ready to start looking at your example:

    ieee754 10^14
0 10000101101 0110101111001100010000011110100100000000000000000000
    ieee754 0.5+10^14
0 10000101101 0110101111001100010000011110100100000000000000100000
    ieee754 <.0.5+10^14
0 10000101101 0110101111001100010000011110100100000000000001000000

Here, we are seeing the same thing as before, but in bit patterns,
rather than in numbers formatted for display. We can see that <. is
increasing the size of the value, but we don't quite understand yet
why that would be.

So here's another view:

    s_e_m 10^14
1  46 1.42108547152020037
    s_e_m 0.5+10^14
1  46 1.42108547152020748
    s_e_m <.0.5+10^14
1  46 1.42108547152021458

We are seeing the same thing again, but now we have something that
might remind us of an epsilon mentioned in the dictionary:

http://www.jsoftware.com/help/dictionary/dx009.htm

9!:18 y
9!:19 y Comparison Tolerance. Queries and sets the comparison
tolerance. See Equal (=). The tolerance in particular cases can be set
using fit, thus: =!.t .

We could work through the math of that, or we could just try it out:

    s_e_m (<.!.0)0.5+10^14
1  46 1.42108547152020037

That looks like the values for 10^14, which I think is what you were expecting.

So, you just need to use <.!.0 instead of <. and that will fix the
problem for you.

Or, if you don't like using !.0 all over the place:

    9!:19]0

    <.0.5+10^14
100000000000000

(But don't blame me if 9!:19]0 breaks some other obscure parts of the
system - you should maybe think about putting that value back to what
it was when you are done. And if you forgot to check before you set
it, and do not feel like restarting J, you can read
http://www.jsoftware.com/help/dictionary/d000.htm which will tell you
what it was.)

Thanks,


----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to