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,

-- 
Raul

On Mon, Aug 22, 2016 at 4:16 AM, Erling Hellenäs
<[email protected]> wrote:
> 0j3 ": 0.5+10^14
>
> 100000000000000.500
>
> The strange result under discussion. How does J create this result?
>
> 0j3 ": <. 0.5+10^14
>
> 100000000000001.000
>
> I must admit I don't understand why this happens. It is loss of precision?
>
> 0j3 ": 0.5+10^15
>
> 1000000000000000.500
>
> Here we have loss of precision:
>
> 0j3 ": 0.5+10^16
>
> 10000000000000000.000
>
> /Erling
>
>
> On 2016-08-20 19:38, Raul Miller wrote:
>>
>> If loss of precision is a problem, you should be using extended precision
>> numbers (or rationals) for your values.
>>
>> And, of course, you should be careful to use operations whose results are
>> extended precision numbers (or rationals) for the values you are working
>> with.
>>
>> For example:
>>
>>     <.1r2+10^13x
>>
>> 10000000000000
>>
>>
>> Thanks,
>>
>>
>
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to