What advanced features do Integer and Float support?
← Getting Started · Ref: Q91
Beyond basic arithmetic (see Q39), EK9 Integer and Float support mod/rem, factorial, bitwise logic, increment/decrement, mixed-type operations, unset propagation, locale formatting, and stream pipelines.
MOD VS REM
Both give the remainder after division, but differ for negative numbers. mod always returns a non-negative result (mathematical modulo). rem preserves the sign of the dividend (like Java %).
17 mod 5 = 2, 17 rem 5 = 2 (identical for positives) -17 mod 5 = 3, -17 rem 5 = -2 (differ for negatives)
mod is useful for wrapping (clock arithmetic, array indexing). rem matches C/Java % behaviour.
FACTORIAL
The ! operator computes factorial:
five <- 5 five! returns 120 (5 * 4 * 3 * 2 * 1)
BITWISE: AND, OR, XOR
Integer supports bitwise logic operators:
a <- 12 b <- 10 a and b = 8, a or b = 14, a xor b = 6
Note that a 0b literal such as 0b11001100 is a Bits value, not an Integer.
IMPORTANT: Integer does NOT have shift operators. Use the Bits type for shifting, rotation, and variable-width bit sequences. Convert with the bits() method: a.bits() gives 1100 and shifting that left by 2 gives 110000.
INCREMENT AND DECREMENT
Both Integer and Float support ++ and --:
counter <- 10 counter++ gives 11, counter-- gives 10 fVal <- 1.5 fVal++ gives 2.5, fVal-- gives 1.5
MIXED FLOAT AND INTEGER OPERATIONS
Float operators accept both Float and Integer arguments:
3.5 * 4 gives Float 14.0, 3.5 + 4 gives Float 7.5
Integer arithmetic operators also accept a Float argument and give a Float:
i <- 4 i * 3.5 gives Float 14.0
Integer comparison operators and compound assignments (< <= > >= == <> += -= *= /=) take an Integer only, so `i < f` with a Float f is E07620 and `i += f` is E50060. Promote with #^ (#^i < f), or put the Float on the left (f < i). See Q25.
UNSET PROPAGATION
Operations involving unset values return unset:
unsetInt <- Integer() propagatedInt <- unsetInt + 1 // is unset unsetFloat <- Float() propagatedFloat <- unsetFloat + 1.0 // is unset
This follows the tri-state principle (see Q29): operations on unknown values produce unknown results.
LOCALE FORMATTING
Both types format through the Locale type:
enGB <- Locale("en_GB") deutsch <- Locale("de_DE") gbText <- enGB.format(1234567) // gives "1,234,567" deText <- deutsch.format(1234567) // gives "1.234.567"
Float adds decimal place control:
gbPi <- enGB.format(3.14159, 2) // gives "3.14" dePi <- deutsch.format(3.14159, 4) // gives "3,1416"
See Q44 for the full Locale API.
FOR-RANGE WITH STEP AND STREAM PIPELINE
Integer integrates with for-range and stream pipelines:
theValues <- List() of Integer intSum <- for i in 1 ... 11 by 2 | tee in theValues | collect as Integer
Generates 1, 3, 5, 7, 9, 11 (step by 2), tees each into theValues, collects the sum (36).
See Q39 for Integer and Float basics (literals, arithmetic, division by zero, promote). See Q40 for the Bits type. See Q44 for full Locale formatting. See Q240 for arithmetic and mathematical operators (mod, rem, abs, sqrt, ^).
Example
defines module qa.numeric.advanced defines program NumericAdvancedDemo() stdout <- Stdout() // === MOD VS REM === stdout.println(`17 mod 5 = ${17 mod 5}`) stdout.println(`17 rem 5 = ${17 rem 5}`) stdout.println(`-17 mod 5 = ${-17 mod 5}`) stdout.println(`-17 rem 5 = ${-17 rem 5}`) // === FACTORIAL === five <- 5 stdout.println(`5! = ${five!}`) // === BITWISE LOGIC === a <- 12 b <- 10 stdout.println(`a and b: ${a and b}`) stdout.println(`a or b: ${a or b}`) stdout.println(`a xor b: ${a xor b}`) // For shift operations, convert to the Bits type bitValue <- a.bits() stdout.println(`Bits of a: ${bitValue}`) shifted <- bitValue << 2 stdout.println(`Shifted left by 2: ${shifted}`) // === INCREMENT AND DECREMENT === counter <- 10 counter++ stdout.println(`After ++: ${counter}`) counter-- stdout.println(`After --: ${counter}`) fVal <- 1.5 fVal++ stdout.println(`Float after ++: ${fVal}`) fVal-- stdout.println(`Float after --: ${fVal}`) // === MIXED FLOAT AND INTEGER === product <- 3.5 * 4 sum <- 3.5 + 4 stdout.println(`3.5 * 4 = ${product}`) stdout.println(`3.5 + 4 = ${sum}`) // === UNSET PROPAGATION === unsetInt <- Integer() propagatedInt <- unsetInt + 1 stdout.println(`Unset int + 1 isSet: ${propagatedInt?}`) unsetFloat <- Float() propagatedFloat <- unsetFloat + 1.0 stdout.println(`Unset float + 1.0 isSet: ${propagatedFloat?}`) // === LOCALE FORMATTING === enGB <- Locale("en_GB") deutsch <- Locale("de_DE") largeNum <- 1234567 stdout.println(`GB: ${enGB.format(largeNum)}`) stdout.println(`DE: ${deutsch.format(largeNum)}`) pi <- 3.141592653589793 stdout.println(`GB 2 decimals: ${enGB.format(pi, 2)}`) stdout.println(`DE 4 decimals: ${deutsch.format(pi, 4)}`) // === FOR-RANGE WITH STEP AND STREAM PIPELINE === theValues <- List() of Integer intSum <- for i in 1 ... 11 by 2 | tee in theValues | collect as Integer stdout.println(`Values: ${theValues}`) stdout.println(`Sum: ${intSum}`)
Common mistakes
E07620 — Integer does NOT have shift operators in EK9. Use the Bits type for shifting, rotation, and variable-width bit sequences. Convert with the bits() method (count.bits()). See ek9 -h E07620 for details.
Incorrect:
shifted <- a << 2
Correct:
shifted <- bitValue << 2
Other ways to ask this
- How do mod, rem, and bitwise operators work on Integer in EK9?
- How do I format numbers with locale-specific separators in EK9?
- What happens when I mix Float and Integer in an expression?
Coming from another language?
Java: % operator (rem semantics only), no factorial operator, bitwise &/|/^/<</>>, Integer.parseInt for locale-agnostic formatting, NumberFormat for locale display, IntStream for range pipelines. Python: % (mod semantics), no factorial operator (use math.factorial), bitwise &/|/^/<</>>, locale module. JavaScript: % (rem semantics), no factorial, bitwise &/|/^/<</>>, Intl.NumberFormat for locale. Rust: % (rem), no factorial, bitwise &/|/^/<</>>, no built-in locale formatting. Go: % (rem), no factorial, bitwise &/|/^/<</>>, no built-in locale formatting. EK9: both mod and rem operators, ! factorial, and/or/xor bitwise (shift on Bits type only), Locale.format() built-in, for-range with stream pipeline integration.
Keywords: stream, unset, intro, rem, mod, beginner, xor, first, or, propagation, start, format, increment, locale, migrate, remainder, bitwise, mixed, pipeline, and, factorial, decrement, advanced