feat(lang): float and double types with ordinary operators

`float` (32-bit) and `double` (64-bit) with + - * / %, comparisons and unary minus.
Decimal literals take their type from context and stay `fixed` elsewhere; int and long
promote implicitly (LUDIC_WARN_FLOAT_PROMOTE=1 lists every promotion). float(), double(),
int(), long() and fixed() convert; floats(n)/doubles(n) buffers; float fields, globals,
constants and parameters; Math.* computes in float for float arguments; string/print
write the shortest round-tripping decimal; float_bits/float_from_bits expose the bits.
@deterministic code may not use floats. The f_* runtime helpers stay as they are.

Editors know the new type words; the JetBrains plugin is 1.5.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-16 16:02:03 +03:00
parent f92d7f89c6
commit e010c2cecc
40 changed files with 67726 additions and 57272 deletions

View file

@ -4,15 +4,15 @@ name: fixed
category: builtins
kind: builtin
tokens: fixed
sig: fixed(n) -> fixed
tip: Lift an integer into a Q16.16 fixed-point value.
sig: fixed(x) -> fixed
tip: Convert an int (or a float) into a Q16.16 fixed-point value.
order: 50
---
Converts an integer into a <code>fixed</code> value (Ludic's Q16.16 fixed-point type), so it can take part in fractional arithmetic. Ludic has no floating point; <code>fixed</code> is how you carry sub-pixel precision for smooth movement and physics-like accumulation. Use <code>fixed</code> when you need to combine an <code>int</code> with fixed-point values or divide to get a fraction — for example <code>fixed(1) / fixed(4)</code> is <code>0.25</code>. Convert back to a whole number for drawing with <code>flr</code>.
Converts an integer into a <code>fixed</code> value (Ludic's Q16.16 fixed-point type), so it can take part in fractional arithmetic. <code>fixed</code> is how you carry deterministic sub-pixel precision for smooth movement and physics-like accumulation; a <code>float</code> or <code>double</code> converts too, truncated toward zero to Q16.16. Use <code>fixed</code> when you need to combine an <code>int</code> with fixed-point values or divide to get a fraction — for example <code>fixed(1) / fixed(4)</code> is <code>0.25</code>. Convert back to a whole number for drawing with <code>flr</code>.
Parameters:
- `n` — the integer to lift into fixed-point
- `x` — the integer (or float) to convert
```ludic
program SmoothAccumulate {

View file

@ -0,0 +1,25 @@
---
id: fn-float
name: float
category: builtins
kind: builtin
tokens: float double
sig: float(x) -> float / double(x) -> double
tip: Convert any number to a float (or double).
order: 51
---
Converts an <code>int</code>, <code>long</code>, <code>fixed</code>, <code>float</code> or <code>double</code> to a <code>float</code> (or, with <code>double(x)</code>, to a <code>double</code>). It is the one conversion that crosses from fixed-point to floating point: `float(fixed(1)) / 4.0` is <code>0.25</code>. A decimal literal converts exactly, so `float(0.1)` is the nearest float to 0.1, not the nearest Q16.16 value.
Parameters:
- `x` — the number to convert
```ludic
program Convert {
entry {
let half = fixed(1) / 2
print(float(half) * 3.0) # 1.5
print(double(7) / 2) # 3.5
}
}
```

View file

@ -0,0 +1,24 @@
---
id: fn-float_bits
name: float_bits
category: builtins
kind: builtin
tokens: float_bits float_from_bits double_bits double_from_bits
sig: float_bits(x) -> int / float_from_bits(bits) -> float
tip: A float's IEEE bit pattern as an int, and back.
order: 53
---
<code>float_bits(x)</code> returns the 32 bits of a <code>float</code> as an <code>int</code>, and <code>float_from_bits(bits)</code> reads them back. <code>double_bits</code> / <code>double_from_bits</code> do the same for a <code>double</code> with a <code>long</code>. Use them where a float has to travel as raw data: a file format, a network packet, or a <code>words</code> buffer shared with code that still stores bit patterns.
Parameters:
- `x` — the float to encode (`float_bits`), or the bits to decode (`float_from_bits`)
```ludic
program Bits {
entry {
print(float_bits(1.0)) # 1065353216 (0x3F800000)
print(float_from_bits(0x40000000)) # 2.0
}
}
```

View file

@ -0,0 +1,25 @@
---
id: fn-int
name: int
category: builtins
kind: builtin
tokens: int long
sig: int(x) -> int / long(x) -> long
tip: Convert a number to a whole number, truncating toward zero.
order: 52
---
Converts a <code>float</code>, <code>double</code>, <code>fixed</code> or <code>long</code> to an <code>int</code> (or, with <code>long(x)</code>, to a <code>long</code>). Floating-point values truncate toward zero, as in C: `int(2.9)` is <code>2</code> and `int(-2.9)` is <code>-2</code>. A <code>fixed</code> value rounds down, like <code>floor</code>. For other rounding use <code>Math.floor</code>, <code>Math.ceil</code> or <code>Math.round</code>.
Parameters:
- `x` — the number to convert
```ludic
program Whole {
entry {
let pixels: float = 12.75
print(int(pixels)) # 12
print(long(pixels * 1000.0)) # 12750
}
}
```