// Плавающая точка: подводные камни IEEE 754
// Компиляция: zig build-exe float_demo.zig && ./float_demo

const std = @import("std");

pub fn main() !void {
    const stdout = std.fs.File.stdout().deprecatedWriter();

    try stdout.print("=== Zig: плавающая точка ===\n\n", .{});

    // 1. Классика: 0.1 + 0.2 != 0.3
    try stdout.print("--- 1. Арифметика ---\n", .{});
    const a: f64 = 0.1;
    const b: f64 = 0.2;
    const c: f64 = 0.3;
    const sum = a + b;
    try stdout.print("0.1 + 0.2 = {d:.20}\n", .{sum});
    try stdout.print("0.3       = {d:.20}\n", .{c});
    try stdout.print("0.1 + 0.2 == 0.3? {}\n\n", .{sum == c});

    // 2. Потеря точности
    try stdout.print("--- 2. Потеря точности ---\n", .{});
    const big: f64 = 1e16;
    const big_plus = big + 1.0;
    try stdout.print("1e16 + 1.0 = {d:.1}\n", .{big_plus});
    try stdout.print("1e16 + 1.0 == 1e16? {}\n\n", .{big_plus == big});

    // 3. NaN
    try stdout.print("--- 3. NaN ---\n", .{});
    const nan = std.math.nan(f64);
    try stdout.print("NaN == NaN? {}\n", .{nan == nan});
    try stdout.print("NaN != NaN? {}\n", .{nan != nan});
    try stdout.print("std.math.isNan(): {}\n\n", .{std.math.isNan(nan)});

    // 4. f32 vs f64
    try stdout.print("--- 4. f32 vs f64 ---\n", .{});
    const f32_val: f32 = 16777217.0; // 2^24 + 1
    const f64_val: f64 = 16777217.0;
    try stdout.print("16777217 как f32: {d:.0}\n", .{@as(f64, f32_val)});
    try stdout.print("16777217 как f64: {d:.0}\n", .{f64_val});
    try stdout.print("f32: 23-bit мантисса, f64: 52-bit мантисса\n\n", .{});

    // 5. Kahan суммирование
    try stdout.print("--- 5. Наивная vs Kahan суммировка ---\n", .{});
    const n: usize = 1_000_000;
    const term: f64 = 0.1;

    var naive_sum: f64 = 0.0;
    for (0..n) |_| {
        naive_sum += term;
    }

    var kahan_sum: f64 = 0.0;
    var comp: f64 = 0.0;
    for (0..n) |_| {
        const y = term - comp;
        const t = kahan_sum + y;
        comp = (t - kahan_sum) - y;
        kahan_sum = t;
    }

    const expected: f64 = @as(f64, @floatFromInt(n)) * term;
    try stdout.print("Ожидание:       {d:.20}\n", .{expected});
    try stdout.print("Наивная сумма:  {d:.20}\n", .{naive_sum});
    try stdout.print("Kahan сумма:    {d:.20}\n", .{kahan_sum});
    try stdout.print("Ошибка наивной: {e:.2}\n", .{@abs(naive_sum - expected)});
    try stdout.print("Ошибка Kahan:   {e:.2}\n", .{@abs(kahan_sum - expected)});
}
