Numbers
Types
| Type | What it is |
|---|---|
Int | an integer of any size |
Float64 | an IEEE 754 double |
Int8 Int16 Int32 Int64 | fixed-width integers, two’s complement |
UInt8 UInt16 UInt32 UInt64 | fixed-width unsigned integers |
Float32 | an IEEE 754 single |
Literals
import uint8 as UInt8
-- | >>> debug mask-- | "240"mask : UInt8mask = 0xf0
million : Intmillion = 1_000_000
flags : Intflags = 0b1010
mode : Intmode = 0o644- An integer literal can be of any number type; a fractional one,
2.5, of a float type. A fractional literal may have an exponent after its digits,6.02e23,1.5e-3; a point comes first,1.0e23, not1e23. It is the float of its type nearest the decimal it writes, rounded once:(1.0000000596046448 : Float32)is theFloat32above 1, not 1.0, as it would be rounded to aFloat64first. Below half the least float of its type it is0.0; beyond the greatest, an error, as is any literal that does not fit its type. debugwrites a float as such a literal, the fewest digits that read back as it:debug 1.0e23is"1.0e23",debug (neg 0.0)is"-0.0".parseFloat sreads such a decimal back, at run time, as a literal is read:parseFloat "0.1"isJust 0.1, and float32’sparseFloat32theFloat32nearest it, rounded once. A-, digits, a point and digits, an exponent (2.5,-1e-7,12.5E+3); anything else ("Infinity","1."," 1") isNothing.- Hexadecimal
0x605, octal0o644and binary0b1010are allowed, and_can separate digits. - The literal must fit its type:
300as aUInt8is an error, and so is1.5as anInt32. - Where nothing decides the type, an integer literal is an
Intand a fractional one aFloat64. In[1, 2.5], both areFloat64.
Negative literals
A - right before a digit is the literal’s sign, unless it comes right
after an operand with no space. So:
| Written | Means |
|---|---|
a - 1, a-1 | subtraction |
f -1 | f applied to -1 |
-128 as an Int8 | its least value |
A - right before a name or ( negates it: -p.x, -(f y). It is the
neg in scope, so it works for any type with a Negation. f -x is
f (-x); - x, with a space, is not a negation.
Operations
Numbers are added, compared and divided by the prelude’s operators, whose theories each number type has: see Operators. How each type divides, rounds and wraps around is with its instances:
IntandFloat64:prelude, and anInt’s bits inint;- the fixed-width integers:
int8,int16,int32,int64,uint8,uint16,uint32,uint64; Float32:float32.
A fixed-width type’s module is imported by a name, as they share their
names (import int64 as Int64), and brings in its instances, so the
prelude’s operators work at its type. One fixed-width type goes to
another by way of an Int:
import int32 as Int32import int8 as Int8
narrow : Int32 -> Int8narrow x = Int8.fromInt (Int32.toInt x)How each backend stores numbers is in Providers.