0

I have a program in which i need to print FLOAT in case of a float number or print INTEGER in case of a regular number.

for Example pseudo code

float num = 1.5; 
if (num mod sizeof(int)==0)
  printf ("INTEGER");
else
  printf("FLOAT");

For example:

  • 1.6 would print "FLOAT"
  • 1.0 would print "INTEGER"

Will something like this work?

undur_gongor
  • 15,657
  • 5
  • 63
  • 75
Vandervidi
  • 295
  • 1
  • 4
  • 11
  • 1
    Are you trying to this in a macro or something? Otherwise, the type is always known. – Mysticial Aug 12 '14 at 21:25
  • 1
    Using `sizeof` will most certainly __not work__. You need to provide a larger example of how you are trying to use this. Otherwise, it's really not clear why you just don't know if it's a float or int. – Bill Lynch Aug 12 '14 at 21:26
  • Instead of pseudo code, please show how you intend to use this in readl code. Because it doesn't really make sense in a language with static variable typing. – Barmar Aug 12 '14 at 21:26
  • Are you trying to distinguish variable types? Or just certain values? – Drew McGowen Aug 12 '14 at 21:27
  • Not using macro. i just need to print 'integer' if the number is not rational and float if it is – Vandervidi Aug 12 '14 at 21:27
  • 2
    Is your question really "How do I determine whether the value of a `float` is a whole number?"? – Oliver Charlesworth Aug 12 '14 at 21:29
  • @OliCharlesworth Look at his edited question, the answer to that should be obvious now. – Barmar Aug 12 '14 at 21:30
  • @Vandervidi: Your original question is a great example of how using example inputs and outputs can __greatly__ clarify a question. In the future, please try to include some example inputs and outputs with your questions. – Bill Lynch Aug 12 '14 at 21:31

4 Answers4

5

All float types have the same size, so your method won't work. You can check if a float is an integer by using ceilf

float num = 1.5; 
if (ceilf(num) == num)
  printf ("INTEGER");
else
  printf("FLOAT");
jh314
  • 27,144
  • 16
  • 62
  • 82
  • 1
    @Vandervidi This isn't really a reliable way to check for integers or compare floating point numbers except in very trivial and predictable cases. See [article](http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm) and I have details in [my answer](http://stackoverflow.com/a/25274580/616460). – Jason C Aug 12 '14 at 21:49
  • 3
    @JasonC: This answer does exactly what the question asks for; it determines whether a floating-point value represents an integer. So it's entirely reliable. – Oliver Charlesworth Aug 12 '14 at 22:11
  • @OliCharlesworth It actually doesn't. Does `powf(powf(3.0f,0.05f),20.0f)` not represent an integer? Mathematically, (3^(1/20))^20 is an integer, and the intention is to perform that calculation -- a result that represents an integer would be expected. Yet this answer claims it is not an integer. It is well known that a blind `==` is not robust for comparing floating-point values, and that round-off error is an issue to be dealt with. Much more care must be taken with floating-point values than with integers. This question also exists for more people than just the OP. – Jason C Aug 13 '14 at 00:15
  • @JasonC: That there are floating-point calculations that don't give mathematically ideal results is a separate issue, IMHO. There are undoubtedly valid reasons for wanting to determine if `num` represents an exact integer value. – Oliver Charlesworth Aug 13 '14 at 07:06
  • @OliCharlesworth All I know is that I hope that nobody searching for "how to determine if a floating point number is an integer" finds this post and calls it a day. – Jason C Aug 13 '14 at 07:10
4

You can use modff():

const char * foo (float num) {
    float x;
    modff(num, &x);
    return (num == x) ? "INTEGER" : "FLOAT";
}

modff() will take a float argument, and break it into its integer and fractional parts. It stores the integer part in the second argument, and the fractional part is returned.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • This fails if the number is slightly different from an integer because of rounding errors from whatever calculations `num` came from. – Jason C Aug 12 '14 at 21:51
  • @Jason C IMO: Numbers that are slightly different from an integer are not integers. The argument provided to such a detection function should be considered exact. This is the quality assessment of math.h functions - the answer provided is based on the assumption that the input was exact. One could make a 2 argument function foo2(x, range_factor) to do more as you suggest. – chux - Reinstate Monica Aug 12 '14 at 22:28
  • Though not much different, suggest `return (modff(num, &x) == 0.0) ? "INTEGER" : "FLOAT";` +1 for best answer either way. – chux - Reinstate Monica Aug 12 '14 at 22:38
  • @chux It depends on the application. If the purpose of the application is to assess math.h functions then yes, an exact comparison is desirable. If the purpose of the application is to do math, a tolerance value would be desirable. Is `powf(powf(3,1/20),20)` not an integer? This answer says it is not. In some applications, maybe not. In others, we actually do want to detect the resulting 2.9999992847442626953125 as an integer. Floating-point round-off is a well-known issue and must be dealt with (if it is significant to the application), or at least remembered. – Jason C Aug 13 '14 at 00:23
  • I.e. This answer isn't *wrong*, for a subset of applications (and perhaps even for the OP's personal needs), but it doesn't have enough information to be *right* for another person who comes here trying to find out how to check if a float is an integer for their own unknown purposes, because it leaves out an important caveat. – Jason C Aug 13 '14 at 00:25
  • @JasonC: This isn't wrong for the question as asked. My answer will precisely tell you if a floating point number consists of only an integral value. The general question of whether two floating point values are equal to each other is answered in the referenced question of which this question has been marked a duplicate. – jxh Aug 13 '14 at 00:32
  • 2
    @JasonC: If you want to ponder a much more curious example, consider the case where [the same floating point number will round to two different values](http://stackoverflow.com/q/16831464/315052). – jxh Aug 13 '14 at 00:37
  • @jxh I suppose there is a difference in our interpretation of what it means for a floating-point number to be a whole number, where your interpretation concentrates less on problem solving and more on the specifics of floating-point bit patterns. Sometimes we want to see if a floating-point value is an integer -- other times we want to see if a floating-point value is an integer. Great example by the way. – Jason C Aug 13 '14 at 00:37
  • 1
    @Jason C `puts(foo(powf(powf(3,1/20),20)));` --> "INTEGER\n". Certainly your compilation will return the same result. `puts(foo(powf(powf(3,1.0/20),20)));` likely will print "FLOAT\n" as typical `double` is really doing something closer to `powf(powf(3,0.05000000000000000278),20)` and should not result in an integer. The `pow()` calls obfuscate the `1.0/20` inexactness of binary FP - the core of the issue. – chux - Reinstate Monica Aug 13 '14 at 03:11
  • 3
    @Jason C A call to determine "integer-ness" of a `double` is simply a call to `modf()`, `ceil()`, etc. A test to determine _near_ "integer-ness" of a `double` is far more complex and needs an additional argument to gauge the "nearness". The nearness (relative, absolute or other) is non-trivial to define and rarely satisfactory for a general purpose solution and, IMO, certainly well beyond OP's request. You points about FP math in-exactness are important, but at the extremity of this post. – chux - Reinstate Monica Aug 13 '14 at 03:12
2

The "easy" way, but with a catch:

You could use roundf, like this:

float z = 1.0f;

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

The problem with this and other similar techniques (such as ceilf) is that, while they work great for whole number constants, they will fail if the number is a result of a calculation that was subject to floating-point round-off error. For example:

float z = powf(powf(3.0f, 0.05f), 20.0f);

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

Prints "fraction", even though (31/20)20 should equal 3, because the actual calculation result ended up being 2.9999992847442626953125.

So how do we deal with this?

Any similar method, be it fmodf or whatever, is subject to this. In applications that perform complex or rounding-prone calculations, usually what you want to do is define some "tolerance" value for what constitutes a "whole number" (this goes for floating-point equality comparisons in general). We often call this tolerance epsilon. For example, lets say that we'll forgive the computer for up to +/- 0.00001 rounding error. Then, if we are testing z, we can choose an epsilon of 0.00001 and do:

if (fabsf(roundf(z) - z) <= 0.00001f) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

You don't really want to use ceilf here because e.g. ceilf(1.0000001) is 2 not 1, and ceilf(-1.99999999) is -1 not -2.

Choose a tolerance value that is appropriate for your application. For more information, check out this article on comparing floating-point numbers.

Community
  • 1
  • 1
Jason C
  • 38,729
  • 14
  • 126
  • 182
  • 2
    It really depends on the application though. If all he cares about is if the float has no decimal parts, then using the epsilon trick will yield the wrong answer (i.e. 1.0000001 should be float) – jh314 Aug 12 '14 at 22:04
  • @jh314 Yes, epsilon should always be chosen based on the application, and "0" could be valid for some applications. However, it's important to place this information in an answer. While the OP may not care, this question is sure to be near the top of search results for "check if float is integer", and completeness helps the world be less incorrect / misinformed. – Jason C Aug 12 '14 at 22:05
1

Will something like this work?

No. For example on the x86_32 and ARM 32 bit architectures sizeof(int) == 4 and sizeof(float) == 4.

Also whatever you think mod is, it clearly shows you don't understand what the sizeof operator does.

datenwolf
  • 159,371
  • 13
  • 185
  • 298