# Numbers in Fable

Fable numbers are very nearly compatible with .NET semantics, but translating into Javascript types has consequences:

• (non-standard) All floating point numbers are implemented as 64 bit (`double`). This makes `float` numbers more accurate than expected.
• (non-standard) Arithmetic integers of 32 bits or less are implemented with different truncation from that expected, as whole numbers embedded within `double`.
• (OK) Conversions between types are correctly truncated.
• (OK) Bitwise operations are all correct, and when made on 32 bit integers are truncated to 32 bits.
• (OK) Longs have a custom implementation which is identical in semantics to .NET and truncates in 64 bits: although it is quite slow.

32 bit integers thus differ from .NET in two ways:

• Underlying 52 bit precision, without expected truncation to 32 bits on overflow. Truncation can be forced if needed by `>>> 0`.
• On exceeding 52 bits absolute value floating point loses precision. So overflow will result in unexpected lower order 0 bits.

The loss of precision can be seen in a single multiplication:

``````((1 <<< 28) + 1) * ((1 <<< 28) + 1) >>> 0
``````

The multiply product will have internal double representation rounded to `0x0100,0000,2000,0000`. When it is truncated to 32 bits by `>>> 0` the result will be `0x2000,0000` not the .NET exact lower order bits value of `0x2000,0001`.

The same problem can be seen where repeated arithmetic operations make the internal (non-truncated) value large. For example a linear congruence random number generator:

``let rng (s:int32) = 10001*s + 12345``

The numbers generated by repeated application of this to its result will all be even after the 4th pseudo-random number, when `s` value exceeds 2^53:

``````let rec randLst n s =
match n with
| 0 -> [s]
| n -> s :: randLst (n-1) (rng s)

List.iter (printfn "%x") (randLst 7 1)``````

The resulting printed list of pseudo-random numbers does not work in Fable:

Fable .Net
1 1
574a 574a
d524223 d524223
6a89e98c 6a89e98c
15bd0684 15bd0685
3d8b8000 3d8be20e
50000000 65ba5527
0 2458c8d0

## Workarounds

• When accurate low-order bit arithmetic is needed and overflow can result in numbers larger than 2^53 use `int64`, `uint64`, which use exact 64 bits, instead of `int32`, `uint32`.
• Alternately, truncate all arithmetic with `>>> 0` or `>>> 0u` as appropriate before numbers can get larger than 2^53:
`let rng (s:int32) = 10001*s + 12345 >>> 0`

## Printing

One small change from .NET in `printf`, `sprintf`, `ToString`. Negative signed integers are printed in hexadecimal format as sign + magnitude, in .Net they are printed as two's complement bit patterns.