Skip to content

Commit 502298f

Browse files
author
Maxime Mangel
committed
Move dotnet compatibility section under JavaScript
1 parent 146254b commit 502298f

File tree

4 files changed

+66
-179
lines changed

4 files changed

+66
-179
lines changed

docs/docs/dotnet/compatibility.md

Lines changed: 0 additions & 104 deletions
This file was deleted.

docs/docs/dotnet/numbers.md

Lines changed: 0 additions & 67 deletions
This file was deleted.

docs/docs/javascript/compatibility.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,69 @@ let inline doesWork(x: 'T) =
167167
168168
doesWork 5
169169
```
170+
171+
## Numeric types
172+
173+
174+
In Fable, we use F# numeric types, which are all translated to JS Number (64-bit floating type) at the exception of `int64`, `uint64`, `bigint` and `decimal`.
175+
176+
Fable numbers are very nearly compatible with .NET semantics, but translating into Javascript types has consequences:
177+
178+
* (non-standard) All floating point numbers are implemented as 64 bit (`double`). This makes `float32` numbers more accurate than expected.
179+
* (non-standard) Arithmetic integers of 32 bits or less are implemented with different truncation from that expected, as whole numbers embedded within `double`.
180+
* (OK) Conversions between types are correctly truncated.
181+
* (OK) Bitwise operations for 64 bit and 32 bit integers are correct and truncated to the appropriate number of bits.
182+
* (non-standard) Bitwise operations for 16 bit and 8 bit integers use the underlying JavaScript 32 bit bitwise semantics. Results are not truncated as expected, and shift operands are not masked to fit the data type.
183+
* (OK) Longs have a custom implementation which is identical in semantics to .NET and truncates in 64 bits, although it is slower.
184+
185+
32 bit integers thus differ from .NET in two ways:
186+
187+
* Underlying 52 bit precision, without expected truncation to 32 bits on overflow. Truncation can be forced if needed by `>>> 0`.
188+
* On exceeding 52 bits absolute value floating point loses precision. So overflow will result in unexpected lower order 0 bits.
189+
190+
The loss of precision can be seen in a single multiplication:
191+
192+
```fsharp
193+
((1 <<< 28) + 1) * ((1 <<< 28) + 1) >>> 0
194+
```
195+
196+
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`.
197+
198+
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:
199+
200+
```fsharp
201+
let rng (s:int32) = 10001*s + 12345
202+
```
203+
204+
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:
205+
206+
```fsharp
207+
let rec randLst n s =
208+
match n with
209+
| 0 -> [s]
210+
| n -> s :: randLst (n-1) (rng s)
211+
212+
List.iter (printfn "%x") (randLst 7 1)
213+
```
214+
215+
The resulting printed list of pseudo-random numbers does not work in Fable:
216+
217+
| Fable | .NET |
218+
|-------:|------:|
219+
|1|1|
220+
|574a|574a
221+
|d524223|d524223|
222+
|6a89e98c|6a89e98c|
223+
|15bd0684|15bd0685|
224+
|3d8b8000|3d8be20e|
225+
|50000000|65ba5527|
226+
|0|2458c8d0|
227+
228+
### Workarounds
229+
230+
* 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`.
231+
* 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`
232+
233+
### Printing
234+
235+
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.

docs/docs/menu.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,6 @@
5656
"docs/typescript/compatibility"
5757
]
5858
},
59-
{
60-
"type": "section",
61-
"label": "From .NET to Fable",
62-
"items": [
63-
"docs/dotnet/compatibility",
64-
"docs/dotnet/numbers"
65-
]
66-
},
6759
{
6860
"type": "section",
6961
"label": "Miscellaneous",

0 commit comments

Comments
 (0)