Quick links:   Flags   Verbs   Functions   Glossary   Release docs

# Arithmetic¶

## Input scanning¶

Numbers in Miller are double-precision float or 64-bit signed integers. Anything scannable as int, e.g `123` or `0xabcd`, is treated as an integer; otherwise, input scannable as float (`4.56` or `8e9`) is treated as float; everything else is a string. Prefixes include `0x` for hexadecimal, e.g. `0xff` is 255 in decimal; `0o` for octal, e.g. `0x377` is 255 in decimal; and `0b`, e.g. `0b1101` is 13 in decimal.

Three flags control input-scanning for numbers: `mlr -O`, `mlr -A`, and `mlr -S`.

Prefix `0x` means hexadecimal, e.g. `0xcafe`; prefix `0b` means binary, e.g. `0b1011`; prefix `0o` means octal, e.g. `0o377`. Numbers in data files with leading zeroes, e.g. `0377` or `06789`, are treated as strings in Miller, unless you specify `mlr -O`: then `0377` will scan as an octal integer (with value 255), and `06789` will scan as a decimal integer (with value 6789).

If you want all numbers from data files to be treated as floats, then you may use `float()` in your filter/put expressions (e.g. replacing `\$c = \$a * \$b` with `\$c = float(\$a) * float(\$b)`). Or, use `mlr -A`.

If you use `mlr -S` then all field values from data files are read in as strings; you can cast them using `int()` or `float()`.

## Conversion by math routines¶

For most math functions, integers are cast to float on input, and produce float output: e.g. `exp(0) = 1.0` rather than `1`. The following, however, produce integer output if their inputs are integers: `+` `-` `*` `/` `//` `%` `abs` `ceil` `floor` `max` `min` `round` `roundm` `sgn`. As well, `stats1 -a min`, `stats1 -a max`, `stats1 -a sum`, `step -a delta`, and `step -a rsum` produce integer output if their inputs are integers.

## Conversion by arithmetic operators¶

The sum, difference, and product of integers is again integer, except for when that would overflow a 64-bit integer at which point Miller converts the result to float.

The short of it is that Miller does this transparently for you so you needn't think about it.

Implementation details of this, for the interested: integer adds and subtracts overflow by at most one bit so it suffices to check sign-changes. Thus, Miller allows you to add and subtract arbitrary 64-bit signed integers, converting only to float precisely when the result is less than -2**63 or greater than 2**63 - 1. Multiplies, on the other hand, can overflow by a word size and a sign-change technique does not suffice to detect overflow. Instead, Miller tests whether the floating-point product exceeds the representable integer range. Now, 64-bit integers have 64-bit precision while IEEE-doubles have only 52-bit mantissas -- so, there are 53 bits including implicit leading one. The following experiment explicitly demonstrates the resolution at this range:

```64-bit integer     64-bit integer     Casted to double           Back to 64-bit
in hex             in decimal                                    integer
0x7ffffffffffff9ff 9223372036854774271 9223372036854773760.000000 0x7ffffffffffff800
0x7ffffffffffffa00 9223372036854774272 9223372036854773760.000000 0x7ffffffffffff800
0x7ffffffffffffbff 9223372036854774783 9223372036854774784.000000 0x7ffffffffffffc00
0x7ffffffffffffc00 9223372036854774784 9223372036854774784.000000 0x7ffffffffffffc00
0x7ffffffffffffdff 9223372036854775295 9223372036854774784.000000 0x7ffffffffffffc00
0x7ffffffffffffe00 9223372036854775296 9223372036854775808.000000 0x8000000000000000
0x7ffffffffffffffe 9223372036854775806 9223372036854775808.000000 0x8000000000000000
0x7fffffffffffffff 9223372036854775807 9223372036854775808.000000 0x8000000000000000
```

That is, one cannot check an integer product to see if it is precisely greater than 2**63 - 1 or less than -2**63 using either integer arithmetic (it may have already overflowed) or using double-precision (due to granularity). Instead, Miller checks for overflow in 64-bit integer multiplication by seeing whether the absolute value of the double-precision product exceeds the largest representable IEEE double less than 2**63, which we see from the listing above is 9223372036854774784. (An alternative would be to do all integer multiplies using handcrafted multi-word 128-bit arithmetic. This approach is not taken.)

## Pythonic division¶

Division and remainder are pythonic:

• Quotient of integers is floating-point unless (unlike Python) exactly representable as integer: `7/2` is `3.5` but `6/2` is `3` (not 3.0).
• Integer division is done with `//`: `7//2` is `3`. This rounds toward the negative.
• Remainders are non-negative: `13 % 10` and `-17 % 10` are both `3`.

## Infinity and NaN¶

You can get IEEE `Inf` and `NaN` in the DSL by `1/0` and `0/0`, respectively. Should you need to, you can also refer to them by name.

Also note that `NaN != NaN` -- this is a general fact of IEEE floating-point arithmetic, nothing to do with Miller. So, like other languages, Miller has an `is_nan` DSL function to check if something is the not-a-number value.

```\$ rlwrap mlr repl
Miller 6.0.0-dev REPL for darwin/amd64/go1.17
Type ':h' or ':help' for online help; ':q' or ':quit' to quit.

[mlr] 1/0
+Inf
[mlr] 0/0
NaN

[mlr] 1/0 == Inf
true
[mlr] 0/0 == NaN
false
[mlr] is_nan(0/0)
true
[mlr] is_nan(NaN)
true

[mlr] ?is_nan
is_nan  (class=typing #args=1) True if the argument is the NaN (not-a-number) floating-point value. Note that NaN has the property that NaN != NaN, so you need 'is_nan(x)' rather than 'x == NaN'.

[mlr] log10(0)
-Inf
[mlr] log10(-2)
NaN
[mlr] is_nan(log10(-2))
true
```

Lastly, note that in Miller, `NaN` is strictly for the use of math-library functions. It doesn't indicate a missing/absent or null value. See also the page on null/empty/absent data.