DEV Community

Andrew Shitov
Andrew Shitov

Posted on • Originally published at andrewshitov.com

Raku: a Language Where 0.1 + 0.2 is 0.3

Programming languages are fascinating. Even if you think that these are the last days when you need to write code yourself, that only gives you more time to enjoy the beauty.

In this article I would like to showcase some of the small but astonishing features of Raku. Even if you never had a chance to install a compiler on your machine, you can run all the examples below in the online Raku playground straight away.

0.1 + 0.2 == 0.3

It is an obvious equation when written on paper, but when you employ floating-point arithmetic, you get a collection of various answers – the price of the trade-off between speed, compactness, and exactness.

In Raku, 0.1 + 0.2 equals 0.3 exactly:

say 0.1 + 0.2 == 0.3;   # True
Enter fullscreen mode Exit fullscreen mode

Run it in the online playground to confirm. In the rest of the article, I will use links like this: 🦋▶ to point you to the playground with the code filled in. All you need is to press the Run button and see the magic.

Similarly, 0.1 + 0.2 - 0.3 is an exact zero. 🦋▶

All this is possible as Raku treats these numbers as belonging to the Rat (rational) type of numbers. 0.1 is a fraction 1/10. 0.2 is the same as 1/5. And while say 1/3 does print a rounded 0.333333, that is only the display: underneath lives the exact , with the numerator and the denominator in easy reach 🦋▶:

say ⅓.numerator;    # 1
say ⅓.denominator;  # 3
Enter fullscreen mode Exit fullscreen mode

And yes, Unicode fractions are understood, together with any kind of digits 🦋▶:

say ⅷ + ٣;   # 11
Enter fullscreen mode Exit fullscreen mode

The here is a single Unicode character – the small Roman numeral eight – and ٣ is the Arabic-Indic digit three, the everyday three for hundreds of millions of people. Raku reads both as the numbers they are.

Superscripts are powers

Raise a number to a power the way your maths teacher wrote it 🦋▶:

say 2⁵;               # 32
say 5² + 12² == 13²;  # True
Enter fullscreen mode Exit fullscreen mode

The second line is the 5–12–13 Pythagorean triple, checked in one readable line.

Integers have no ceiling

An integer in Raku is as long as it needs to be. There is no 64-bit cliff to fall off, no special "big integer" import – the numbers simply grow 🦋▶:

say 2¹⁰⁰;         # 1267650600228229401496703205376
say 10¹⁸ × 10¹⁸;  # 1 followed by 36 zeroes
say [*] 1 .. 100;
Enter fullscreen mode Exit fullscreen mode

The square brackets in the last line are the reduction meta-operator: [*] places * between all the numbers of the range, so you get the factorial of 100 – all 158 digits of it:

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Enter fullscreen mode Exit fullscreen mode

Primality included

Number theory is on board too 🦋▶:

say 97.is-prime;          # True
say (2¹²⁷ − 1).is-prime;  # True
Enter fullscreen mode Exit fullscreen mode

The second number is a Mersenne prime of 39 digits, tested as casually as the small one. Notice the minus sign in 2¹²⁷ − 1: it is not the ASCII hyphen but the true Unicode minus, and Raku is perfectly happy with either.

Operators from the maths textbook

Superscripts are not the only notation rescued from the maths textbook. The multiplication and division signs, and the comparison signs with the slash already crossed through, are all ordinary Raku operators 🦋▶:

say 7 × 6;      # 42
say 10 ÷ 4;     # 2.5
say 1 ≤ 2 ≤ 3;  # True
say 2 ≠ 3;      # True
Enter fullscreen mode Exit fullscreen mode

× and ÷ are the real multiplication and division operators (the ASCII * and / work too, of course). Comparisons chain the way they do in mathematics: 1 ≤ 2 ≤ 3 is a single condition, not a syntax error. And 10 ÷ 4 is the familiar Rat story again – the exact fraction 5/2, whose decimal display 2.5 this time needs no rounding at all.

Chaining also combines with the reduction meta-operator you met at the factorial: put between the square brackets, and [≤] chains it across every neighbouring pair of a list – a ready-made test that the list is sorted 🦋▶:

say [≤] 1, 2, 5, 9;  # True
say [≤] 3, 1, 2;     # False
Enter fullscreen mode Exit fullscreen mode

π, τ, and ∞

The constants you know from school are predefined 🦋▶:

say π;           # 3.141592653589793
say τ == 2 × π;  # True
Enter fullscreen mode Exit fullscreen mode

(Type pi and tau if the Greek letters are far from your keyboard.) Infinity is a value in its own right: you can compare things with it, and you can build a range of all positive integers and politely take the first five 🦋▶:

say ∞ > 10¹⁰⁰;     # True
say (1 .. ∞)[^5];  # (1 2 3 4 5)
Enter fullscreen mode Exit fullscreen mode

The range is lazy, so nobody attempts to materialise the rest of it.

And when you do want floating point

Floats did not go anywhere – you ask for them with scientific notation 🦋▶:

say 0.1e0 + 0.2e0;  # 0.30000000000000004
Enter fullscreen mode Exit fullscreen mode

0.1e0 is a Num, an honest IEEE double, and with it comes the famous constant from the beginning of this article. Floats remain the right tool for physics and simulations; Raku simply refuses to make them the default meaning of a decimal literal.

Where this runs

Every example above runs in the raku.online playground, which is powered by Raku++, an independent implementation of Raku compiled to WebAssembly – the interpreter works entirely in your browser page. The reference implementation of the language is Rakudo, and everything shown here prints exactly the same on both.

The next article in this series opens the second cabinet of curiosities: Unicode – strings that count a seven-codepoint emoji as one character, a variable named , and a file called café-☕.txt.

Top comments (0)