#@cos() Precision Problem

1 messages · Page 1 of 1 (latest)

knotty harness
#

Code:

const zMath = std.math;

pub const Pi: f32 = 3.14159265358979311599796346854;
pub const Deg2Rad: f32 = Pi / 180.0;

/// Returns the cosine of `x` (measured in radians).
pub inline fn Cos(value: anytype) f32 {
    const T = @TypeOf(value);
    const info = @typeInfo(T);
    return switch (info) {
        .Float => return zMath.cos(value),
        .ComptimeFloat, .Int, .ComptimeInt => return zMath.cos(@as(f32, value)),
        else => @compileError("Unsupported type"),
    };
}

pub fn main() void {
    std.debug.print("Val: {d}\n", .{Cos(0 * Math.Deg2Rad)});
    std.debug.print("Val: {d}\n", .{Cos(30 * Math.Deg2Rad)});
    std.debug.print("Val: {d}\n", .{Cos(45 * Math.Deg2Rad)});
    std.debug.print("Val: {d}\n", .{Cos(60 * Math.Deg2Rad)});
    std.debug.print("Val: {d}\n", .{Cos(90 * Math.Deg2Rad)});
}

Console:

Val: 1
Val: 0.8660253882408142
Val: 0.7071067690849304
Val: 0.4999999701976776
Val: -0.00000004371138828673793

cos(90) should be 1. But somehow I'm losing precision on calculation. What am I doing wrong? Can It be Deg2Rad? I guess it is correct on first 6 fractal. Maybe I should round to ceil?

proven yacht
#

cos(90) should be zero and the result seems to be within f32 precision range (ca. 7 digits)

knotty harness
proven yacht
#

To begin with it's not printing "much more", the leading zeros in cos(90) do not count as precision of the result, but they do count when you estimate the error (the error should be measured relatively to argument roughly speaking).

#

As for why it generally prints more than 7 digits, idk, could be details of Zig std formatting.

#

But AFAIK on the good side, Zig formatting guarantees fp -> ascii -> fp roundtrip (at least potentially), which AFAIK quite a number of formatting libraries don't.

#

You still can limit the number of printed digits using formatting options

knotty harness
#

how about cos 60. it should be 0.5000000...... something, right? is the problem about the Pi number? Or should I go and learn computer float math :D?

proven yacht
#

in math yes, in floating point no

#

there is always or almost always precision loss in floating point

#

your results seem to be well within that precision (the absolute error ca. 1e-7, which should be the case for arguments of the order of magnitude of 1.0)

#

it's generally not possible to give much more precise results, even with a better cos function, since your argument already has some precision losses embedded in it

#

if your experience with other formatting libraries is different, then either they are "deceving" you in a way, rounding results upon printing, or maybe you were using more than 32-bit precision, I would guess

knotty harness
#

thanks for the informations. You have opened my mind about the situation.

proven yacht
#

Actually your results have ca. 15 digits, which suggests that they assume f64 precision. But your calculations are done in f32, hence you see so much discrepancy.

knotty harness
#

I raised to f64 in calculations and it is more accurate now. I started with f32 because I don't need more precision. But even cos 60 is staring getting away from real math result. I think, I should stay in f64 precision zone.

proven yacht
#

I would question whether you need more that 1e-7 relative precision generally. But if you don't care too much about performance and/or memory, it should be much safer to simply switch to f64.