Function to map double to long number

Maybe this is a slightly less common question, but I would like to find a function that can convert the double (c) number to the long (c) number. No need to save duplicate information. The most important thing:

 double a,b; long c,d; c = f(a); d = f(b); 

This should be true:

if (a < b) , then c < d for all a,b double and for all c,d long

Thank you everybody.

+7
c function double long-integer
source share
3 answers

Your requirement is possible if the following two conditions are met:

While the second condition is fulfilled on each widely used platform, the first condition does not.

If both do conditions are stored on your platform, you can implement this function as follows:

 long f(double x) { if (x > 0) return double_to_long(x); if (x < 0) return -double_to_long(-x); return 0; } 

You have several ways to implement the conversion function:

 long double_to_long(double x) { long y; memcpy(&y,&x,sizeof(x)); return y; } long double_to_long(double x) { long y; y = *(long*)&x; return y; } long double_to_long(double x) { union { double x; long y; } u; ux = x; return uy; } 

Please note that the second option is not recommended because it violates the strict anti-aliasing rule.

+5
source share

There are four basic conversions from floating point to integer types:

 floor - Rounds towards negative infinity, ie next lowest integer. ceil[ing] - Rounds towards positive infinity, ie next highest integer. trunc[ate] - Rounds towards zero, ie strips the floating-point portion and leaves the integer. round - Rounds towards the nearest integer. 

None of these transformations will give the behavior you specified, but floor will allow a slightly weaker condition (a < b) implies (c <= d) .

If the double value uses more space for the presentation than a long , then there is no matching that might fit your original constraint, thanks to the dove principle. In principle, since the double type can represent much more different values ​​than the long type, there is no way to preserve the strict partial order of the < relation, since several double values ​​will be forced to match the same long value.

See also:

+1
source share

Use frexp() to get you mostly. It splits the number into exponential and value (fraction).

Suppose long is at least the same size as double , otherwise it is pointless. Pigeonhole principle .

 #include <math.h> long f(double x) { assert(sizeof(long) >= sizeof(double)); #define EXPOWIDTH 11 #define FRACWIDTH 52 int ipart; double fraction = frexp(fabs(x), &ipart); long lg = ipart; lg += (1L << EXPOWIDTH)/2; if (lg < 0) ipart = 0; if (lg >= (1L << EXPOWIDTH)) lg = (1L << EXPOWIDTH) - 1; lg <<= FRACWIDTH; lg += (long) (fraction * (1L << FRACWIDTH)); if (x < 0) { lg = -lg; } return lg; } 

-

Notes:

The eigenvalue for EXPO depends on DBL_MAX_EXP and DBL_MIN_EXP and information about the double type.

This solution displays the same double values ​​near the extrema of the double . I will look and test later.


Otherwise, as stated above: superimpose two types.

Since long often 2 additions, and double is laid out using the sign method, additional work is required when double negative. Also watch out for -0.0.

 long f(double x) { assert(sizeof x == sizeof (long)); union { double d; long lg; } u = { x*1.0 }; // *1.0 gets rid of -0.0 // If 2 complement - which is the common situation if (u.lg < 0) { u.lg = LONG_MAX - u.lg; } return u.lg; } 
+1
source share

All Articles