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:

  0b11001100 and 0b10101010 = 0b10001000
  0b11001100 or 0b10101010 = 0b11101110
  0b11001100 xor 0b10101010 = 0b01100110

IMPORTANT: Integer does NOT have shift operators. Use the Bits type for shifting, rotation, and variable-width bit sequences. Convert with Bits(integerValue).

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 operators only accept Integer. To convert Integer to Float, use #^ promote (see Q25).

UNSET PROPAGATION

Operations involving unset values return unset:

  unsetInt <- Integer()
  unsetInt + 1 is unset
  unsetFloat <- Float()
  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:

  Locale("en_GB").format(1234567) gives "1,234,567"
  Locale("de_DE").format(1234567) gives "1.234.567"

Float adds decimal place control:

  Locale("en_GB").format(3.14159, 2) gives "3.14"
  Locale("de_DE").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 ===

      x <- 0b11001100
      y <- 0b10101010

      stdout.println(`x and y: ${x and y}`)
      stdout.println(`x or y: ${x or y}`)
      stdout.println(`x xor y: ${x xor y}`)

      // For shift operations, use the Bits type
      bitValue <- Bits(x)
      stdout.println(`Bits of x: ${bitValue}`)

      // === 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

E50001 — Integer does NOT have shift operators in EK9. Use the Bits type for shifting, rotation, and variable-width bit sequences. Convert with Bits(integerValue). See ek9 -h E50001 for details.

Incorrect:

shifted <- x << 2

Correct:

bitValue <- Bits(x)
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: locale, increment, format, start, propagation, or, first, xor, beginner, mod, rem, intro, unset, stream, advanced, decrement, factorial, and, pipeline, mixed, bitwise, remainder, migrate