# Floating Point Numbers

### Floating Point Numbers

Floating point numbers are numbers with fractional parts.

Examples:

```zig
const price = 19.99;
const temperature = -3.5;
const pi = 3.14159;
```

Integers store whole numbers. Floating point numbers store approximate real numbers.

Use integers for counts:

```zig
const files: u32 = 12;
```

Use floating point numbers for measurements:

```zig
const height: f64 = 1.75;
const weight: f64 = 68.5;
```

#### The main floating point types

Zig provides several floating point types:

| Type | Size | Common use |
|---|---:|---|
| `f16` | 16 bits | compact numeric data, graphics, machine learning |
| `f32` | 32 bits | games, graphics, large numeric arrays |
| `f64` | 64 bits | general decimal calculations |
| `f80` | 80 bits | extended precision on some targets |
| `f128` | 128 bits | high precision calculations |

For beginners, the most important types are:

```zig
f32
f64
```

Use `f64` when you want a safe default for ordinary numeric code. Use `f32` when memory size and speed matter, especially when storing many numbers.

#### Declaring floating point values

You can write the type explicitly:

```zig
const pi: f64 = 3.14159;
const speed: f32 = 12.5;
```

Zig can also infer the type in many local contexts:

```zig
const x = 3.14;
```

However, for public APIs, struct fields, and important calculations, writing the type explicitly is often clearer.

```zig
const Circle = struct {
    radius: f64,
};
```

This tells the reader exactly what kind of number the program stores.

#### Basic arithmetic

Floating point arithmetic uses the familiar operators:

```zig
const a: f64 = 10.0;
const b: f64 = 4.0;

const sum = a + b;
const difference = a - b;
const product = a * b;
const quotient = a / b;
```

Here, `quotient` is `2.5`.

Unlike integer division, floating point division keeps the fractional part.

```zig
const x: f64 = 10.0 / 4.0; // 2.5
```

#### Floating point numbers are approximate

This is the most important beginner lesson.

Many decimal numbers cannot be represented exactly in binary floating point.

For example, the decimal number `0.1` looks simple to humans, but it does not have an exact finite representation in binary. The computer stores a nearby value.

So this can surprise you:

```zig
const std = @import("std");

pub fn main() void {
    const x: f64 = 0.1 + 0.2;

    std.debug.print("{d}\n", .{x});
}
```

You may expect exactly:

```text
0.3
```

But internally, the value is only approximately `0.3`.

This does not mean floating point is broken. It means floating point is designed for approximate numeric computation, not exact decimal accounting.

#### Do not compare floats carelessly

Because floats are approximate, direct equality can be dangerous.

This may not behave as you expect:

```zig
const x: f64 = 0.1 + 0.2;

if (x == 0.3) {
    // maybe not reached
}
```

A better approach is to compare with a small tolerance.

```zig
const std = @import("std");

fn nearlyEqual(a: f64, b: f64, tolerance: f64) bool {
    return @abs(a - b) < tolerance;
}

pub fn main() void {
    const x: f64 = 0.1 + 0.2;

    if (nearlyEqual(x, 0.3, 0.000001)) {
        std.debug.print("close enough\n", .{});
    }
}
```

This asks whether two numbers are close enough, instead of asking whether their binary representations are exactly the same.

#### Special floating point values

Floating point types can represent some special values.

One is infinity.

```zig
const inf = std.math.inf(f64);
```

Another is NaN, which means “not a number.”

```zig
const nan = std.math.nan(f64);
```

NaN can appear in invalid numeric operations, such as some forms of undefined mathematical calculation.

A key property of NaN is that it is not equal to anything, including itself.

```zig
const std = @import("std");

pub fn main() void {
    const x = std.math.nan(f64);

    std.debug.print("{}\n", .{x == x}); // false
}
```

This is unusual, but it follows floating point rules.

#### Printing floating point numbers

Use `std.debug.print` as usual.

```zig
const std = @import("std");

pub fn main() void {
    const pi: f64 = 3.14159;
    const temperature: f32 = 22.5;

    std.debug.print("pi = {d}\n", .{pi});
    std.debug.print("temperature = {d}\n", .{temperature});
}
```

Output:

```text
pi = 3.14159
temperature = 22.5
```

The `{d}` formatter prints a decimal value.

#### Scientific notation

You can write large or small floating point numbers using scientific notation.

```zig
const large: f64 = 1.5e6;   // 1,500,000
const small: f64 = 2.5e-3;  // 0.0025
```

The `e` means “times ten to the power of.”

```text
1.5e6 means 1.5 * 10^6
2.5e-3 means 2.5 * 10^-3
```

Scientific notation is common in physics, graphics, simulations, and numerical code.

#### Converting between integers and floats

Zig does not silently convert integers and floats in many situations. You usually make the conversion explicit.

To convert an integer to a float, use `@floatFromInt`:

```zig
const count: u32 = 10;
const count_float: f64 = @floatFromInt(count);
```

To convert a float to an integer, use `@intFromFloat`:

```zig
const value: f64 = 42.9;
const whole: i32 = @intFromFloat(value);
```

This discards the fractional part.

```text
42.9 becomes 42
```

Be careful. If the float value cannot fit into the integer type, that is a problem.

```zig
const value: f64 = 1_000_000_000_000.0;
const small: i32 = @intFromFloat(value); // too large for i32
```

Zig makes this conversion explicit because it can lose information.

#### Float size matters

An `f32` uses less memory than an `f64`.

If you store one number, this usually does not matter.

If you store millions of numbers, it can matter a lot.

```zig
const PointF32 = struct {
    x: f32,
    y: f32,
};

const PointF64 = struct {
    x: f64,
    y: f64,
};
```

A `PointF32` stores two 32-bit floats.

A `PointF64` stores two 64-bit floats.

For a huge array of points, `f32` may use half the memory. But `f64` gives more precision.

This is a common tradeoff in systems programming.

#### Floating point and money

Do not use binary floating point for exact money calculations.

This is risky:

```zig
const price: f64 = 19.99;
```

It may look fine for printing, but internally it is approximate.

For money, prefer storing the smallest unit as an integer.

```zig
const price_cents: i64 = 1999;
```

This means `$19.99` stored as `1999` cents.

Then addition and subtraction are exact:

```zig
const a: i64 = 1999;
const b: i64 = 250;

const total_cents = a + b; // 2249
```

This is a good general rule: use floating point for measurements, not exact accounting.

#### A complete example

```zig
const std = @import("std");

fn circleArea(radius: f64) f64 {
    const pi: f64 = 3.141592653589793;
    return pi * radius * radius;
}

pub fn main() void {
    const radius: f64 = 5.0;
    const area = circleArea(radius);

    std.debug.print("radius = {d}\n", .{radius});
    std.debug.print("area = {d}\n", .{area});
}
```

Output:

```text
radius = 5
area = 78.53981633974483
```

The function takes an `f64` and returns an `f64`.

```zig
fn circleArea(radius: f64) f64
```

That means the input and output are both floating point numbers.

#### The main idea

Floating point numbers are for approximate numeric values.

They are useful for measurements, graphics, simulations, geometry, physics, and many scientific calculations. They are not ideal for exact decimal values such as money.

For beginner Zig code, use `f64` when you need a floating point number. Use `f32` when memory size matters or an API specifically expects it.

