digitalmars.D.learn - What is a concise way to test if floating point value is integral?
- Paul Jurczak (6/6) Aug 28 2013 I'm writing this rather ugly:
- Paul Jurczak (5/11) Aug 28 2013 I defined a helper function:
- Jonathan M Davis (7/15) Aug 28 2013 There may be something in std.math which makes it cleaner, but I would h...
- Paul Jurczak (5/23) Aug 28 2013 Isn't type conversion:
- Jonathan M Davis (7/37) Aug 29 2013 Not really IMHO. std.conv.to does fancier conversions than casting does,...
- Paul Jurczak (8/10) Aug 29 2013 On Thursday, 29 August 2013 at 07:51:40 UTC, Jonathan M Davis
- Jonathan M Davis (19/33) Aug 29 2013 Sure, they will. float has 32 bits, just like int, so it can't possibly ...
- Paul Jurczak (10/56) Aug 29 2013 I should have used "integer" instead of "integral" to avoid math
- JS (13/76) Aug 29 2013 Yes, casting will not work because a float type can't be fully
- anonymous (9/27) Aug 29 2013 float can't hold more distinct values than int, but a float can
- Simen Kjaeraas (18/34) Aug 29 2013 First, that's showing the exact opposite of what you're saying it does.
I'm writing this rather ugly: sqrt(cast(float)D) != round(sqrt(cast(float)D) line and I'm looking for more concise notation without introducing a meaningless variable to hold expression being tested. Is there an equivalent of std.math.trunc(), which would return fractional portion instead, maybe frac()?
Aug 28 2013
On Thursday, 29 August 2013 at 05:47:43 UTC, Paul Jurczak wrote:I'm writing this rather ugly: sqrt(cast(float)D) != round(sqrt(cast(float)D) line and I'm looking for more concise notation without introducing a meaningless variable to hold expression being tested. Is there an equivalent of std.math.trunc(), which would return fractional portion instead, maybe frac()?I defined a helper function: bool isIntegral(T)(T x) {return x == round(x);} but is there something in D libraries to give me this functionality?
Aug 28 2013
On Thursday, August 29, 2013 07:47:16 Paul Jurczak wrote:I'm writing this rather ugly: sqrt(cast(float)D) != round(sqrt(cast(float)D) line and I'm looking for more concise notation without introducing a meaningless variable to hold expression being tested. Is there an equivalent of std.math.trunc(), which would return fractional portion instead, maybe frac()?There may be something in std.math which makes it cleaner, but I would have thought that the to test whether a floating point value is an integral value, you'd just cast it to an integral type and then compare that against the original. e.g. auto isIntegral = cast(int)my_float == my_float; - Jonathan M Davis
Aug 28 2013
On Thursday, 29 August 2013 at 06:23:18 UTC, Jonathan M Davis wrote:On Thursday, August 29, 2013 07:47:16 Paul Jurczak wrote:Isn't type conversion: auto isIntegral = to!int(my_float) == my_float; more recommended/idiomatic D way to deal with built-in types?I'm writing this rather ugly: sqrt(cast(float)D) != round(sqrt(cast(float)D) line and I'm looking for more concise notation without introducing a meaningless variable to hold expression being tested. Is there an equivalent of std.math.trunc(), which would return fractional portion instead, maybe frac()?There may be something in std.math which makes it cleaner, but I would have thought that the to test whether a floating point value is an integral value, you'd just cast it to an integral type and then compare that against the original. e.g. auto isIntegral = cast(int)my_float == my_float; - Jonathan M Davis
Aug 28 2013
On Thursday, August 29, 2013 08:50:47 Paul Jurczak wrote:On Thursday, 29 August 2013 at 06:23:18 UTC, Jonathan M Davis wrote:Not really IMHO. std.conv.to does fancier conversions than casting does, and it throws in cases of overflow, neither of which are of any benefit when converting a float to an int, as any integral value in a float will fit in an int. Using to would just create extra overhead for no extra benefit in this case. - Jonathan M DavisOn Thursday, August 29, 2013 07:47:16 Paul Jurczak wrote:Isn't type conversion: auto isIntegral = to!int(my_float) == my_float; more recommended/idiomatic D way to deal with built-in types?I'm writing this rather ugly: sqrt(cast(float)D) != round(sqrt(cast(float)D) line and I'm looking for more concise notation without introducing a meaningless variable to hold expression being tested. Is there an equivalent of std.math.trunc(), which would return fractional portion instead, maybe frac()?There may be something in std.math which makes it cleaner, but I would have thought that the to test whether a floating point value is an integral value, you'd just cast it to an integral type and then compare that against the original. e.g. auto isIntegral = cast(int)my_float == my_float; - Jonathan M Davis
Aug 29 2013
On Thursday, 29 August 2013 at 07:51:40 UTC, Jonathan M Davis wrote: [..]as any integral value in a float will fit in an int.[..] Will it? Most of them will not fit, but cast to int produces nonsensical value anyway as in this example: cast(int)float.max With to!int you get a proper warning.
Aug 29 2013
On Thursday, August 29, 2013 10:07:31 Paul Jurczak wrote:On Thursday, 29 August 2013 at 07:51:40 UTC, Jonathan M Davis wrote: [..]Sure, they will. float has 32 bits, just like int, so it can't possibly hold a value larger than an int can hold. This code passes with flying colors foreach(i; int.min .. int.max) assert(cast(float)i == i);as any integral value in a float will fit in an int.[..] Will it? Most of them will not fitbut cast to int produces nonsensical value anyway as in this example: cast(int)float.maxSo what? All you care about here is whether the value in the float is an integral value. float.max isn't an integral value, so it really doesn't matter if you get overflow when converting. It would have to convert back to the exact same value when converting it back to a float, and it won't. assert(cast(int)float.max == float.max); will fail. It might make more sense to use to!int if you want to use the resulting int for something, but all you're doing with it is comparing it against the original float to see if it's the same value. If anything, the fact that to!int throws would be a serious problem for what you're trying to do, because if what you're testing for is whether a float holds an integral value, throwing on overflow when converting to int would just get in your way. It should just result in false in that case (because it's not an integral value, or it wouldn't overflow), and the cast will result in false, unlike to!int. - Jonathan M Davis
Aug 29 2013
On Thursday, 29 August 2013 at 08:26:11 UTC, Jonathan M Davis wrote:On Thursday, August 29, 2013 10:07:31 Paul Jurczak wrote:I should have used "integer" instead of "integral" to avoid math vs. programming language confusion. Well, float.max is an integer number! Its value is 3.40282e+38. The function I defined at the top of this page: bool isIntegral(T)(T x) {return x == round(x);} works correctly with float.max. Using cast(int) fails. I should have written it as: bool isInteger(T)(T x) {return x == round(x);}On Thursday, 29 August 2013 at 07:51:40 UTC, Jonathan M Davis wrote: [..]Sure, they will. float has 32 bits, just like int, so it can't possibly hold a value larger than an int can hold. This code passes with flying colors foreach(i; int.min .. int.max) assert(cast(float)i == i);as any integral value in a float will fit in an int.[..] Will it? Most of them will not fitbut cast to int produces nonsensical value anyway as in this example: cast(int)float.maxSo what? All you care about here is whether the value in the float is an integral value. float.max isn't an integral value, so it really doesn't matter if you get overflow when converting. It would have to convert back to the exact same value when converting it back to a float, and it won't. assert(cast(int)float.max == float.max); will fail. It might make more sense to use to!int if you want to use the resulting int for something, but all you're doing with it is comparing it against the original float to see if it's the same value. If anything, the fact that to!int throws would be a serious problem for what you're trying to do, because if what you're testing for is whether a float holds an integral value, throwing on overflow when converting to int would just get in your way. It should just result in false in that case (because it's not an integral value, or it wouldn't overflow), and the cast will result in false, unlike to!int. - Jonathan M Davis
Aug 29 2013
On Thursday, 29 August 2013 at 08:58:02 UTC, Paul Jurczak wrote:On Thursday, 29 August 2013 at 08:26:11 UTC, Jonathan M Davis wrote:Yes, casting will not work because a float type can't be fully cast to an int without possible overflow. Your method works fine. The only issue, the issue with comparing any floating point, is tolerance. How close to an int does a float have to be to be considered an int? If you can afford to do something like `return (abs(x - round(x)) < tol)`. (remember, numerical computations can result in floating point numbers that are suppose be integers but are not(accumulation of rounding errors). Using == results in using the tolerance of a float, its minimum value) Also look at FXTRACT.On Thursday, August 29, 2013 10:07:31 Paul Jurczak wrote:I should have used "integer" instead of "integral" to avoid math vs. programming language confusion. Well, float.max is an integer number! Its value is 3.40282e+38. The function I defined at the top of this page: bool isIntegral(T)(T x) {return x == round(x);} works correctly with float.max. Using cast(int) fails. I should have written it as: bool isInteger(T)(T x) {return x == round(x);}On Thursday, 29 August 2013 at 07:51:40 UTC, Jonathan M Davis wrote: [..]Sure, they will. float has 32 bits, just like int, so it can't possibly hold a value larger than an int can hold. This code passes with flying colors foreach(i; int.min .. int.max) assert(cast(float)i == i);as any integral value in a float will fit in an int.[..] Will it? Most of them will not fitbut cast to int produces nonsensical value anyway as in this example: cast(int)float.maxSo what? All you care about here is whether the value in the float is an integral value. float.max isn't an integral value, so it really doesn't matter if you get overflow when converting. It would have to convert back to the exact same value when converting it back to a float, and it won't. assert(cast(int)float.max == float.max); will fail. It might make more sense to use to!int if you want to use the resulting int for something, but all you're doing with it is comparing it against the original float to see if it's the same value. If anything, the fact that to!int throws would be a serious problem for what you're trying to do, because if what you're testing for is whether a float holds an integral value, throwing on overflow when converting to int would just get in your way. It should just result in false in that case (because it's not an integral value, or it wouldn't overflow), and the cast will result in false, unlike to!int. - Jonathan M Davis
Aug 29 2013
On Thursday, 29 August 2013 at 08:26:11 UTC, Jonathan M Davis wrote:On Thursday, August 29, 2013 10:07:31 Paul Jurczak wrote:float can't hold more distinct values than int, but a float can have integer values greater than int.max. (Also, there are int values that a float cannot store.)On Thursday, 29 August 2013 at 07:51:40 UTC, Jonathan M Davis wrote: [..]Sure, they will. float has 32 bits, just like int, so it can't possibly hold a value larger than an int can hold.as any integral value in a float will fit in an int.[..] Will it? Most of them will not fitThis code passes with flying colors foreach(i; int.min .. int.max) assert(cast(float)i == i);That's because both sides are casted to float. [...]float.max isn't an integral value,It's not a value that an int can store, but it's an integer in the mathematical sense.
Aug 29 2013
On 2013-08-29, 10:25, Jonathan M Davis wrote:On Thursday, August 29, 2013 10:07:31 Paul Jurczak wrote:First, that's showing the exact opposite of what you're saying it does. Second, it doesn't even show that. Your code is equivalent to: foreach(i; int.min .. int.max) assert(cast(float)i == cast(float)i); If that does not pass with flying colors, I'd be surprised. Now try this: foreach(i; int.min .. int.max) { float f = i; // DMD optimizes out cast(int)cast(float)int assert(cast(int)f == i); } It will fail for odd numbers in the range 16,777,216-33,554,432, and for numbers not divisible by 4 in the range to the next power of two, then 8, and so on. These numbers are simply not representable by a float. For more information: http://floating-point-gui.de/formats/fp/ -- SimenOn Thursday, 29 August 2013 at 07:51:40 UTC, Jonathan M Davis wrote: [..]Sure, they will. float has 32 bits, just like int, so it can't possibly hold a value larger than an int can hold. This code passes with flying colors foreach(i; int.min .. int.max) assert(cast(float)i == i);as any integral value in a float will fit in an int.[..] Will it? Most of them will not fit
Aug 29 2013