2 ms·
Could you give some examples where the same value needs to be used in integer and floating-point math? I'm not quite sure if I understood you correctly, but in
by themulticaster 5y ago
Could you give some examples where the same value needs to be used in integer and floating-point math?
I'm not quite sure if I understood you correctly, but in case you propose that integer <-> float conversion should happen implicitly I have to disagree. While implicitly converting from integer to float/double would probably be fine, implicitly converting from float/double to integer sounds like a recipe for headaches: There are just too many options (truncation/ceil/floor/rounding). Even if you decided that some option should be the standard since it makes sense in 90% of all cases (let's say rounding), you now have a difficult-to-find (since it's implicit) footgun ready to cause damage in the remaining 10% of all cases.
Even in that paragraph lies a small surprise waiting to be found (at least for some people): The floating point standard IEEE 754 defines five different rounding modes - two "normal" modes (Round to nearest, ties to even as well as Round to nearest, ties away from zero) and the additional directed ones mentioned above (truncation, ceil, floor). Interestingly, the default rounding mode (Round to nearest, ties to even) is not the one you probably learnt in school (that would be Round to nearest, ties away from zero). In school, you always round up if you end up exactly between two numbers, i.e. round(0.5) = 1, round(1.5) = 2. However, this introduces a small bias that can manifest itself into a real problem, for example if you round many measurements and then calculate the mean. That's why the default floating-point rounding mode will essentially alternate between rounding up and down, i.e. round(0.5) = 0 and round(1.5) = 2.
Most of the time this is not an issue and you really want the default rounding mode, but I hope this example illustrates why hiding the "implementation detail" of converting floating-point numbers to integers might not be a good idea.
By the way, I just looked up the man page for round(), and to my surprise found that it will always round ties away from zero, independently of the floating-point environment. If you want to round using different rounding modes in C, you apparently have to use nearbyint() and friends after setting up the rounding mode using fesetround().
PS: Of course the rounding modes are all about rounding floating-point values, not necessarily converting them to integers, but I think the point should be clear.
- huachimingo 5y ago>Could you give some examples where the same value needs to be used in integer and floating-point math? When you want to draw a pong game in a finite matrix representation, like a screen in ncurses, you cannot have something like screen[2.1][3.5], so you have to truncate (or round, depending what you want to do) the same float coordinates to write that matrix. Of course, you could avoid these using fixed point but even there you need a type conversion.
- flohofwoe 5y ago> Could you give some examples where the same value needs to be used in integer and floating-point math? Mainly when working with pixels. In some contexts, pixels are clearly integer values (for instance the width and height of a texture in a 3D API is almost always given as integers, a texture with a width of 12.5 pixels simply doesn't make sense). Computations on 2D pixel coordinates on the other hand need to have subpixel precision, otherwise you'll get jittering artefacts. This results in code where integer values must be converted to floating point before going into computations, and sometimes the results need to be converted back to integer. I started to add duplicate functions to my C APIs to reduce the need for explicit conversions when using those APIs from stricter languages like Zig or Rust, for instance: void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left); void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left); PS: interestingly, even 3D-APIs don't agree here. For instance in OpenGL, the glViewport() function takes integer values, while in D3D11 and Metal a viewport is defined with floating point values.
- pornel 5y agoI agree that float<>int conversions are evil. I would make an exception for int to float conversion for literals. When switching from C to Rust I was annoyed by: if x > 0 not compiling, because that's an integer zero, not a float zero! This makes the compiler feel very petty.
- darthrupert 5y agoTo me that seems equivalent to complaining that the following fails to compile: if 0 == "0" ... which is obviously broken code.
- joppy 5y agoThe number 0 happily and unambiguously plays a role in many numeric types and algebraic structures, and it’s kind of nice if the compiler can just figure out the type that it should be from context. Comparing a literal 0 to a double should cast to a double, comparing a literal 0 to an int should cast to an int, etc. I would be happy for “(int) 0 == (double) 0” to raise a type error though. I guess it’s a matter of interpretation: does “x == 0” mean that we are comparing x with the integer zero, or the “zero value” of the same type as x? Numeric code is difficult for many reasons, but something that can make it much more tractable is having the code as close as possible to the mathematics underlying the algorithms, and this kind of “polymorphic constant” behaviour can help a lot, especially for integer literals which unambiguously embed into essentially any numeric type you could think of.