Integer part of double

A

Alex Vinokur

Ho to get valid value of integer part of double _as int value_?

Here is a program that demonstrate the problem.

------ foo.c ------
#include <stdio.h>
#include <math.h>

int main ()
{
double d1 = 0.0;
double d1i = 0.0;
double d1f = 0.0;
int i1 = 0;
int i2 = 0;
size_t k = 0;

for (k = 0; k < 1000; k++)
{
d1 = d1 + 1.1;
i1 = (int) d1;

d1f = modf (d1, & d1i);
i2 = (int) d1i;

if ( ((d1 - i1) > 0.95) || ((d1i - i2) > 0.95) )
{
printf ("i1 = %3d, i2 = %3d, d1 = %10f, d1 = %16.12f, d1i =
%10f%\n", i1, i2, d1, d1, d1i);
}

}
return 0;
}
-------------------


------ Run ------
i1 = 10, i2 = 10, d1 = 11.000000, d1 = 11.000000000000, d1i =
10.000000
i1 = 76, i2 = 76, d1 = 77.000000, d1 = 77.000000000000, d1i =
76.000000
i1 = 87, i2 = 87, d1 = 88.000000, d1 = 88.000000000000, d1i =
87.000000
i1 = 98, i2 = 98, d1 = 99.000000, d1 = 99.000000000000, d1i =
98.000000
i1 = 109, i2 = 109, d1 = 110.000000, d1 = 110.000000000000, d1i =
109.000000
i1 = 120, i2 = 120, d1 = 121.000000, d1 = 121.000000000000, d1i =
120.000000
i1 = 131, i2 = 131, d1 = 132.000000, d1 = 132.000000000000, d1i =
131.000000
i1 = 142, i2 = 142, d1 = 143.000000, d1 = 143.000000000000, d1i =
142.000000
i1 = 153, i2 = 153, d1 = 154.000000, d1 = 154.000000000000, d1i =
153.000000
i1 = 164, i2 = 164, d1 = 165.000000, d1 = 165.000000000000, d1i =
164.000000
i1 = 175, i2 = 175, d1 = 176.000000, d1 = 175.999999999999, d1i =
175.000000
i1 = 186, i2 = 186, d1 = 187.000000, d1 = 186.999999999999, d1i =
186.000000
i1 = 197, i2 = 197, d1 = 198.000000, d1 = 197.999999999999, d1i =
197.000000
i1 = 208, i2 = 208, d1 = 209.000000, d1 = 208.999999999999, d1i =
208.000000
i1 = 219, i2 = 219, d1 = 220.000000, d1 = 219.999999999999, d1i =
219.000000
i1 = 230, i2 = 230, d1 = 231.000000, d1 = 230.999999999999, d1i =
230.000000
i1 = 241, i2 = 241, d1 = 242.000000, d1 = 241.999999999999, d1i =
241.000000
i1 = 252, i2 = 252, d1 = 253.000000, d1 = 252.999999999999, d1i =
252.000000
i1 = 263, i2 = 263, d1 = 264.000000, d1 = 263.999999999999, d1i =
263.000000
i1 = 274, i2 = 274, d1 = 275.000000, d1 = 274.999999999999, d1i =
274.000000
i1 = 285, i2 = 285, d1 = 286.000000, d1 = 286.000000000000, d1i =
285.000000
i1 = 296, i2 = 296, d1 = 297.000000, d1 = 297.000000000000, d1i =
296.000000
-----------------


Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 
U

user923005

Alex said:
Ho to get valid value of integer part of double _as int value_?

If the value is positive then floor() seems a natural solution.
If the value is negative then ceil() seems a natural solution.

Keep in mind that on most machines an integer is not large enough to
hold all possible floor()/ceil() values from a double. Don't forget
that 1e222 is a very large integer.

If you insist on storing the value in an integral type, then I would at
least use a long long unless you know for sure that you will never need
more than 10 digits.

Maybe something like this:

#include <limits.h>
#include <math.h>
int intpart(double input, double *dint, long long *lint)
{
if (input > 0)
*dint = floor(input);
else
*dint = ceil(input);

if (*dint < LLONG_MAX) {
*lint = (long long) *dint;
return 1;
} else {
lint = 0;
return 0;
}
}
 
R

Richard Heathfield

Alex Vinokur said:
Ho to get valid value of integer part of double _as int value_?

int m = d;

If it doesn't fit, you've got problems.

long int n = d;

might solve those problems, but of course it might not.

If you just want to suppress decimals in your output, you don't have to do
any conversion - you can simply printf("%.0f\n", d);
 
U

user923005

Richard said:
Alex Vinokur said:


int m = d;

If it doesn't fit, you've got problems.

long int n = d;

might solve those problems, but of course it might not.

If you just want to suppress decimals in your output, you don't have to do
any conversion - you can simply printf("%.0f\n", d);

Of course, that rounds, rather than truncates.
 
R

Richard Heathfield

user923005 said:
Of course, that rounds, rather than truncates.

Oh, good spot. In which case, we're back to your suggestion of floor() and
ceil(), I suppose - but I *think* he's primarily interested in suppressing
trailing 0s in his output (admittedly I'm just guessing), so floor() and
ceil() wouldn't be enough on their own.
 
A

Alex Vinokur

Richard Heathfield wrote:
[snip]
I *think* he's primarily interested in suppressing
trailing 0s in his output (admittedly I'm just guessing), so floor() and
ceil() wouldn't be enough on their own.
[snip]

I am interested in the following:

double d;
int i;

d = 15.3; // after some calculation
i = (int) d; // i == 15; It is what I want to get

d = 15.0; // after some calculation
i = (int) d; // sometimes i == 15, sometimes i == 14; I want always
to get i == 15


Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 
R

Richard Heathfield

Alex Vinokur said:
Richard Heathfield wrote:
[snip]
I *think* he's primarily interested in suppressing
trailing 0s in his output (admittedly I'm just guessing), so floor() and
ceil() wouldn't be enough on their own.
[snip]

I am interested in the following:

double d;
int i;

d = 15.3; // after some calculation
i = (int) d; // i == 15; It is what I want to get

You don't need the cast.

i = d; is sufficient.
d = 15.0; // after some calculation
i = (int) d; // sometimes i == 15, sometimes i == 14; I want always
to get i == 15

Floating-point math is inherently imprecise (because computers aren't
terribly good at fitting infinity into N bits, for finite values of N). So
you'll probably find that d is actually 14.99999something. The fix is to
add a tiny number to it, big enough to nudge it over the wire if it's just
below, but not so big as to nudge it over the /next/ wire if it's actually
some way above.

So, for example, i = d + 0.001; may be acceptable to you. Or i = d +
DBL_EPSILON; - it all really depends on what you consider to be "darn it,
this is 15 even though the computer thinks it's below that", and what you
consider to be 14 even though the computer thinks it's above that. That is,
you have to choose a cut-off point.
 
M

micans

Richard said:
user923005 said:


Oh, good spot. In which case, we're back to your suggestion of floor() and

printf("%.0f\n", d-0.5)

this may give -0 in the range 0.0-0.5, and to truncate towards zero one
needs to do

if (d < 0.0) {
printf("%.0f\n", d+0.5)
else {
printf("%.0f\n", d-0.5)
}

Stijn
 
E

Eric Sosman

Alex said:
Richard Heathfield wrote:
[snip]
I *think* he's primarily interested in suppressing
trailing 0s in his output (admittedly I'm just guessing), so floor() and
ceil() wouldn't be enough on their own.
[snip]

I am interested in the following:

double d;
int i;

d = 15.3; // after some calculation
i = (int) d; // i == 15; It is what I want to get

d = 15.0; // after some calculation
i = (int) d; // sometimes i == 15, sometimes i == 14; I want always
to get i == 15

In the second case, "some calculation" probably arrives
at a value that is very close to 15, but not precisely equal
to it -- you get 15.00000011432, perhaps. Converting this
to an integer chops off the fractional part, producing 15.

But what if the calculated result is just a tiny bit
small, like 14.99999987856? Converting this to int again
chops the fraction, but this time you get 14. What you
probably need to do is not to truncate the number by
converting directly to integer, but to round it first
and then convert.

If you have a C99 implementation, this is easy:

#include <math.h>
...
i = round(d);

The round() function is not part of the C90 Standard,
so you might need to do it by hand (but check the documentation;
by now, some "C90 implementations" are actually "C90 plus some
C99 goodies" if you invoke them suitably). Here's a crude but
reasonably effective way:

i = (d >= 0) ? d + 0.5 : d - 0.5;
 
C

CBFalconer

Alex said:
.... snip ...

I am interested in the following:

double d;
int i;

d = 15.3; // after some calculation
i = (int) d; // i == 15; It is what I want to get

d = 15.0; // after some calculation
i = (int) d; // sometimes i == 15, sometimes i == 14; I want
always to get i == 15

i = d + 0.5; /* no casts needed - they are usually errors */

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
 
S

soccertl

Alex said:
Richard Heathfield wrote:
[snip]
I *think* he's primarily interested in suppressing
trailing 0s in his output (admittedly I'm just guessing), so floor() and
ceil() wouldn't be enough on their own.
[snip]

I am interested in the following:

double d;
int i;

d = 15.3; // after some calculation
i = (int) d; // i == 15; It is what I want to get

d = 15.0; // after some calculation
i = (int) d; // sometimes i == 15, sometimes i == 14; I want always
to get i == 15


Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn

Why not just use the modf routine?

double d, x, y;

d = 15.3;
x = modf(d, &y);

x will then have 15 only and y will have whatever the 3 represents
(whether it is actually 3 or .298). You can then print them out as
doubles or whatever representation you like.
 
S

soccertl

soccertl said:
Alex said:
Richard Heathfield wrote:
[snip]
I *think* he's primarily interested in suppressing
trailing 0s in his output (admittedly I'm just guessing), so floor() and
ceil() wouldn't be enough on their own.
[snip]

I am interested in the following:

double d;
int i;

d = 15.3; // after some calculation
i = (int) d; // i == 15; It is what I want to get

d = 15.0; // after some calculation
i = (int) d; // sometimes i == 15, sometimes i == 14; I want always
to get i == 15


Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn

Why not just use the modf routine?

double d, x, y;

d = 15.3;
x = modf(d, &y);

x will then have 15 only and y will have whatever the 3 represents
(whether it is actually 3 or .298). You can then print them out as
doubles or whatever representation you like.

By the way, you could then test "y" to see if it is >= .5 and if it is
then add 1 to "x".
 
K

Keith Thompson

Alex Vinokur said:
Richard Heathfield wrote:
[snip]
I *think* he's primarily interested in suppressing
trailing 0s in his output (admittedly I'm just guessing), so floor() and
ceil() wouldn't be enough on their own.
[snip]

I am interested in the following:

double d;
int i;

d = 15.3; // after some calculation
i = (int) d; // i == 15; It is what I want to get

d = 15.0; // after some calculation
i = (int) d; // sometimes i == 15, sometimes i == 14; I want always
to get i == 15

What result do you want if d == 15.9? 15.7? 15.5?
 
C

CBFalconer

user923005 said:
CBFalconer wrote:
[snip]
i = d + 0.5; /* no casts needed - they are usually errors */

Suppose that d contains -14.42
i now contains -13

If you are worrying about -ve values, do as someone else suggested
and use:

i = d + (d < 0) ? -0.5 : 0.5;
 
K

Keith Thompson

Alex Vinokur said:
Keith Thompson wrote:
[snip]
What result do you want if d == 15.9? 15.7? 15.5?

Also 15.

[snip]

Based on that, you want either trunc() or floor(), depending on how
you want to treat negative numbers.

But earlier, you said (or at least implied) that you want 15.9999+ to
map to 16. You need to decide how close to an integer the number
needs to be before you round it up rather than down.
 
A

Alex Vinokur

K

Keith Thompson

Alex Vinokur said:
Keith said:
Alex Vinokur said:
Keith Thompson wrote:
[snip]
What result do you want if d == 15.9? 15.7? 15.5?

Also 15.

[snip]

Based on that, you want either trunc() or floor(), depending on how
you want to treat negative numbers.

trunc() is not ANSI C; floor() doesn't solve the problem.

trunc() is C99; it should be easy enough to re-implement it in C90.

(Historical note: ANSI introduced the first C standard in 1989. ISO
adopted it, with editorial changes, in 1990; ANSI then adopted the ISO
C90 standard. ISO introduced the new C99 standard in 1999; this was
also adopted by ANSI. So strictly speaking, C99 is ANSI C, though the
term is often applied to the (formally obsolete) C89/C90 standard.)

floor() does map 15.9, 15.7, and 15.5 to 15. If that doesn't solve
your problem, you need to define your problem more precisely, perhaps
by addressing the portions of my article that you snipped.

Upthread, you wrote:

| d = 15.0; // after some calculation
| i = (int) d; // sometimes i == 15, sometimes i == 14; I want always
| to get i == 15

Obviously d isn't really equal to 15.0; it's 14.999something.

So 15.9 maps to 16, but 15.9999..., for enough 9s, maps to 16. You
need to decide exactly where the result changes.

And you need to decide what to do with negative numbers.

Precisely defining the problem is a large part of solving it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top