Floating-point Numbers
Let’s take a look at floating-point numbers:
const std = @import("std");
const print = std.debug.print;
pub fn main() void {
var a: f64 = 1.2; // 64-bit float
a /= 3.0;
print("a = {}\n", .{a});
}$ zig run float.zig
a = 0.39999999999999997
Formatted output
We can get nicer formatted output by setting the precision:
const std = @import("std");
const print = std.debug.print;
pub fn main() void {
const a: f64 = 1.2 / 3.0;
print("a = {:.4}\n", .{a});
}$ zig run formatted.zig
a = 1.2000
Printing with {e} gives us scientific
notation:
const std = @import("std");
const print = std.debug.print;
pub fn main() void {
const me = 5.9722e24;
print("mass of the earth ≈ {} kg\n", .{me});
print("mass of the earth ≈ {e} kg\n", .{me});
}$ zig run scientific.zig
mass of the earth ≈ 5972200000000000000000000 kg
mass of the earth ≈ 5.9722e24 kg
Functions
std.math has functions for nan (“not a number”) and inf (“infinity”).
const std = @import("std");
const print = std.debug.print;
const math = std.math;
pub fn main() void {
const nan = math.nan(f64);
const inf = math.inf(f64);
print("{} + {} = {}\n", .{ nan, 1.0, nan + 1.0 });
print("{} + {} = {}\n", .{ nan, nan, nan + nan });
print("{} - {} = {}\n", .{ inf, 1.0, inf - 1.0 });
print("{} - {} = {}\n", .{ inf, inf, inf - inf });
}$ zig run special.zig
nan + 1 = nan
nan + nan = nan
inf - 1 = inf
inf - inf = -nan
Some common mathematical functions are available as builtin functions:
const std = @import("std");
const print = std.debug.print;
const math = std.math;
pub fn main() void {
print("sin pi = {:7.4}\n", .{@sin(math.pi)});
print("cos pi = {:7.4}\n", .{@cos(math.pi)});
print("log e = {:7.4}\n", .{@log(math.e)});
}$ zig run functions.zig
sin pi = 0.0000
cos pi = -1.0000
log e = 1.0000
There are also builtin functions to convert floats to integers:
const std = @import("std");
const math = std.math;
const expect = std.testing.expect;
test "float-to-int conversion" {
try expect(@floor(1.9) == 1); // round down
try expect(@floor(-1.1) == -2);
try expect(@ceil(1.1) == 2); // round up
try expect(@ceil(-1.9) == -1);
try expect(@trunc(1.9) == 1); // round towards
try expect(@trunc(-1.9) == -1); // zero
try expect(@round(1.5) == 2); // round to the
try expect(@round(-1.5) == -2); // closest integer
}$ zig test convert.zig
All 1 tests passed.
Floating-point types
f64 is a good default choice, but Zig has four more
floating-point types:
const std = @import("std");
const print = std.debug.print;
pub fn main() void {
const x16: f16 = 1.0 / 3.0;
const x32: f32 = 1.0 / 3.0;
const x64: f64 = 1.0 / 3.0;
const x80: f80 = 1.0 / 3.0;
const x128: f128 = 1.0 / 3.0;
print(" 16 bit: 1/3 = {}\n", .{x16});
print(" 32 bit: 1/3 = {}\n", .{x32});
print(" 64 bit: 1/3 = {}\n", .{x64});
print(" 80 bit: 1/3 = {}\n", .{x80});
print("128 bit: 1/3 = {}\n", .{x128});
}$ zig run types.zig
16 bit: 1/3 = 0.3333
32 bit: 1/3 = 0.33333334
64 bit: 1/3 = 0.3333333333333333
80 bit: 1/3 = 0.33333333333333333334
128 bit: 1/3 = 0.3333333333333333333333333333333333
Comparing floating-point numbers
There’s also the usual comparison operators.
const std = @import("std");
const expect = std.testing.expect;
test "comparison operators" {
try expect(1.0 == 1.0);
try expect(1.0 != 2.0);
try expect(1.0 >= 1.0 and 2.0 >= 1.0);
try expect(2.0 > 1.0);
try expect(1.0 <= 1.0 and 1.0 <= 2.0);
try expect(1.0 < 2.0);
}$ zig test comparison.zig
All 1 tests passed.
== and != are usually not the right choice
for floating-point numbers. The standard library has functions we can
use instead:
const std = @import("std");
const math = std.math;
const expect = std.testing.expect;
test "approximate comparison operators" {
const a: f64 = 0.00123;
const b: f64 = 0.001234;
// comparison with tolerance
try expect(math.approxEqAbs(f64, a, b, 1e-5));
try expect(!math.approxEqAbs(f64, a, b, 1e-6));
// comparison with relative tolerance
try expect(math.approxEqRel(f64, a, b, 0.01));
try expect(!math.approxEqRel(f64, a, b, 0.001));
// wrapper functions in std.testing
try std.testing.expectApproxEqAbs(a, b, 1e-5);
try std.testing.expectApproxEqRel(a, b, 0.01);
}$ zig test approx.zig
All 1 tests passed.
Next example: Functions.