Float

A float stores a number with a decimal point, like 3.14 or -0.001. It gives you about 15 significant digits of precision — enough for scientific work, games, and most real-world maths. When you write a number with a decimal point in Loft, it is automatically a float.

fn main() {

Write a decimal point in a literal and Loft treats the whole expression as a float. The usual arithmetic operators (+, -, *, /) all work the way you would expect.

  assert(1.5 + 0.5 == 2.0, "Float addition");
  assert(3.0 / 2.0 == 1.5, "Float division");
  assert(2.0 * 1.5 == 3.0, "Float multiplication");

The f suffix selects single-precision floats, which take half the memory of a regular float but have fewer decimal digits of accuracy. This trade-off is common in graphics and audio code where exact decimal values matter less than speed or memory.

  x = 0.1f + 2 * 1.0f;
  assert(x == 2.1f, "Single precision float");

as float converts an integer to a float so you can mix them in calculations. Putting a float inside {...} converts it to text for display. You can also go the other way: "1.5" as float parses the text back to a number.

  assert(3 as float == 3.0, "Integer to float");
  assert("1.5" as float == 1.5, "Text to float");
  assert("{1.5}" == "1.5", "Float formatted as text");

Formatting Floats

Put a colon after the value inside {...} to control how it looks. {value:width.precision}width is the minimum number of characters printed (padded with spaces on the left); precision fixes the number of decimal places. You can use either part on its own: {value:.2} just fixes decimal places, {value:5} just sets the minimum width.

  assert("{1.2:4.2}" == "1.20", "Float with width and precision");
  assert("{334.1:.2}" == "334.10", "Float with precision only");
  assert("{1.4:5}" == "  1.4", "Float with width only");

Math Functions

PI is a built-in constant (approximately 3.14159265358979). Multiplying it by 1000 and rounding gives 3142, which confirms the value is correct.

  assert(round(PI * 1000.0) == 3142.0, "PI constant");

pow(base, exponent) raises a number to a power — this is exponentiation. Note: ^ in Loft is bitwise XOR, NOT exponentiation. Always use pow() for powers. log(value, base) is the inverse: log(x, b) answers "b to the what power equals x?" Here: 4^5 = 1024, and log(1024, 2) = 10 because 2^10 = 1024.

  assert(log(pow(4.0, 5), 2) == 10.0, "log base 2 of 4^5");

sin and cos work in radians, not degrees. A full circle is 2*PI radians; a half circle (180 degrees) is PI radians. sin(PI) should be exactly zero but computers use approximations for decimal numbers, so you may get something like 0.0000000001 instead. We use ceil() to round it up to 0. cos(PI) is exactly -1, so the whole expression ceil(~0 + -1 * 1000) lands at -1000.

  assert(ceil(sin(PI) + cos(PI) * 1000) == -1000.0, "sin and cos");

abs() returns the absolute value — the distance from zero, always non-negative. Useful any time you care about magnitude but not direction.

  assert(abs(-2.5) == 2.5, "Absolute value of float");

round() picks the nearest whole number (0.5 rounds up). ceil() always rounds up to the next whole number, even for 2.01. floor() always rounds down to the previous whole number, even for 2.99. All three give back a float, not an integer — so 3.0, not 3.

  assert(round(2.6) == 3.0, "round up");
  assert(round(2.4) == 2.0, "round down");
  assert(ceil(2.1) == 3.0, "ceil");
  assert(floor(2.9) == 2.0, "floor");

Single-precision floats work inside format strings just like regular floats.

  assert("a{0.1f + 2 * 1.0f}b" == "a2.1b", "Single-precision format");
}