#Why does this it complain about f32 when casting to f32?

1 messages · Page 1 of 1 (latest)

gaunt imp
#
sprite.box.width = @intFromFloat(@as(f32, sprite.texture.height) / @as(f32, sprite.texture.width) * @as(f32, sprite.box.height));

All of the values here are c_int. I am trying to convert everything to float to do math, but return another c_int. Why does it say "expected f32"??

src/main.zig:176:65: error: expected type 'f32', found 'c_int'
        sprite.box.width = @intFromFloat(@as(f32, sprite.texture.height) / @as(f32, sprite.texture.width) * @as(f32, sprite.box.height));
                                                  ~~~~~~~~~~~~~~^~~~~~~

I tried to test the same thing using some basic non struct values, and it works. What is going on? Why does it work below but not work above ??

pub fn main() void {
    const a:c_int = 2;
    const b:c_int = 3;
    
    // works
    const r:f32 = @as(f32, a) / @as(f32, b) * @as(f32, a);
    std.debug.print("Hello, {d}!\n", .{r});
    
    // works
    const s:c_int = @intFromFloat(@as(f32, a) / @as(f32, b) * @as(f32, a));
    std.debug.print("Hello, {d}!\n", .{s});
}
#

I never imagined a programming language where basic math would be hard. 🙂

vernal phoenix
#

in your last code snippet, the values a and b are comptime-known, so comptime evaluation, which has more lenient typing rules, computes the entire thing. for runtime known integers you'll have to use an explicit @floatFromInt cast

gaunt imp
#

Oh, thanks! That makes sense now that its explained. Much appreciated.

#

Wow, this feels extreme. It works, but wow, its just a basic a*b/c. Maybe I am doing something wrong.

#
        sprite.box.width = @intFromFloat(@as(f32, @floatFromInt(sprite.texture.height)) / @as(f32, @floatFromInt(sprite.texture.width)) * @as(f32, @floatFromInt(sprite.box.height)));
vernal phoenix
#

btw, why do you cast the integers to floats, just to later cast the result into an int again? can't you do:

sprite.box.width = sprite.texture.height * sprite.box.height / sprite.texture.width;
```instead?
gaunt imp
#

Its all pixel widths inside raylib.

#

Two are defined as c_int by raylib.h, and the end result goes back into raylib. So ultimately there is no use for a float (except for trying to be accurate in the scaling of a sprite)

#

Oh, actually, the multiplication can be done as an int I guess:

        sprite.box.width = @intFromFloat(@as(f32, @floatFromInt(sprite.texture.height)) / @as(f32, @floatFromInt(sprite.texture.width * sprite.box.height)));
vernal phoenix
#

this is a different equation, you're doing a/(b*c) now, instead of a/b*c

gaunt imp
#

Mathematiclaly the same.

#

Unless the multiplication causes an overflow

vernal phoenix
#

order of operations, ya know

gaunt imp
#

oh

#

damn

#

Thanks, you saved me.

jaunty flame
#

i also stumbled on this at first. im not sure if theres a technical term for this, but zig's casting goes by destination, not by source. So, @floatFromInt doesnt know by default what its casting into what, like at all. You have to tell it. you can do this with something like @as. but you can also do it by explicitly typing a variable. For example:

var foo: i32 = 5;
// these are equivalent:
var bar: f32 = @floatFromInt(foo);
var bar = @as(f32, @floatFromInt(foo));

foo is runtime, but 5 is comptime. by extension, 5 is a comptime int; Casting it to i32 happens at comptime. this is the lenience.
However, then trying to assign an int to a float like var bar: f32 = foo; will result in an error, because foo is only runtime known, so it cannot check to ensure it will be a valid float. (this becomes more apparent when working with say an i8 vs i32, with overflow checking)
All of this to say that @floatFromInt is the sortof "runtime mechanism" to convert from one number type to another. and its "return type" is entirely dependant on what you're trying to assign it to; in mostly the same way as comptime int can be checked and converted to an i32 at comptime, when assigned to an i32 for example.

jaunty robin
#

You'd usually introduce temporary symbols to avoid huge expressions with type conversions in middle

#

also by using temporary symbols, you can avoid @as all over the place by specifying the symbol's type instead

#

introducing temporary constants won't impact runtime performance, they can be optimised well, no point throwing it all into one expression