www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What is a concise way to test if floating point value is integral?

reply "Paul Jurczak" <pauljurczak yahoo.com> writes:
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
next sibling parent "Paul Jurczak" <pauljurczak yahoo.com> writes:
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
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
parent reply "Paul Jurczak" <pauljurczak yahoo.com> writes:
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:
 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
Isn't type conversion: auto isIntegral = to!int(my_float) == my_float; more recommended/idiomatic D way to deal with built-in types?
Aug 28 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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:
 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
Isn't type conversion: auto isIntegral = to!int(my_float) == my_float; more recommended/idiomatic D way to deal with built-in types?
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 Davis
Aug 29 2013
parent reply "Paul Jurczak" <pauljurczak yahoo.com> writes:
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
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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:
 [..]
 
 as any integral value in a float will fit in an
 int.
[..] Will it? Most of them will not fit
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);
 but cast to int produces
 nonsensical value anyway as in this example:
 
 cast(int)float.max
So 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
next sibling parent reply "Paul Jurczak" <pauljurczak yahoo.com> writes:
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:
 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
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);
 but cast to int produces
 nonsensical value anyway as in this example:
 
 cast(int)float.max
So 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
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);}
Aug 29 2013
parent "JS" <js.mdnq gmail.com> writes:
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:
 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:
 [..]
 
 as any integral value in a float will fit in an
 int.
[..] Will it? Most of them will not fit
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);
 but cast to int produces
 nonsensical value anyway as in this example:
 
 cast(int)float.max
So 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
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);}
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.
Aug 29 2013
prev sibling parent "anonymous" <anonymous example.com> writes:
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:
 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
Sure, they will. float has 32 bits, just like int, so it can't possibly hold a value larger than an int can hold.
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.)
 This 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
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-08-29, 10:25, Jonathan M Davis wrote:

 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:
 [..]

 as any integral value in a float will fit in an
 int.
[..] Will it? Most of them will not fit
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);
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/ -- Simen
Aug 29 2013