Функция для отображения двойного в длинное число
Может быть, это немного редкий вопрос, но я хотел бы найти функцию, способную преобразовать double
(с число) в long
(с номером). Нет необходимости сохранять двойную информацию. Самое главное это:
double a,b;
long c,d;
c = f(a);
d = f(b);
Это должно быть правдой
если
(a < b)
затемc < d
для всехa,b double
и для всехc,d long
Спасибо всем вам.
3 ответа
Ваше требование выполнимо, если выполняются следующие два условия:
- Компилятор определяет
sizeof(double)
такой же какsizeof(long)
- Аппаратное обеспечение использует двоичный формат IEEE 754 с двойной точностью
В то время как 2-е условие выполняется на каждой широко используемой платформе, 1-е условие не выполняется.
Если на вашей платформе выполняются оба условия, вы можете реализовать эту функцию следующим образом:
long f(double x)
{
if (x > 0)
return double_to_long(x);
if (x < 0)
return -double_to_long(-x);
return 0;
}
У вас есть несколько разных способов реализовать функцию преобразования:
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;
u.x = x;
return u.y;
}
Обратите внимание, что второй вариант не рекомендуется, поскольку он нарушает правило строгого наложения имен.
Использование frexp()
чтобы вы были в основном там. Он делит число на экспоненту и значимость (дробь).
Предполагать long
по крайней мере такой же размер, как double
в остальном это бессмысленно. Принцип голубиных отверстий.
#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;
}
-
Заметки:
Подходящее значение для EXPO зависит от DBL_MAX_EXP
а также DBL_MIN_EXP
и подробности double
тип.
Это решение отображает то же самое double
значения, близкие к крайним double
, Я посмотрю и опробую больше позже.
В противном случае, как указано выше: наложение двух типов.
Как long
часто дополняют 2 и double
выложен в значительном размере, дополнительная работа необходима, когда double
отрицательно. Также следите за -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's complement - which is the common situation
if (u.lg < 0) {
u.lg = LONG_MAX - u.lg;
}
return u.lg;
}
Существует четыре основных преобразования из типов с плавающей точкой в целочисленные:
floor - Rounds towards negative infinity, i.e. next lowest integer.
ceil[ing] - Rounds towards positive infinity, i.e. next highest integer.
trunc[ate] - Rounds towards zero, i.e. strips the floating-point portion and leaves the integer.
round - Rounds towards the nearest integer.
Ни одно из этих преобразований не даст указанное вами поведение, но floor
позволит немного более слабое состояние (a < b) implies (c <= d)
,
Если double
значение использует больше места для представления, чем long
тогда нет никакого сопоставления, которое могло бы соответствовать вашему начальному ограничению, благодаря принципу голубиных отверстий. В основном, так как double
Тип может представлять гораздо больше различных значений, чем long
типа, нет никакого способа сохранить строгий частичный порядок <
отношения, как множественные double
значения будут вынуждены сопоставить с тем же long
значение.
Смотрите также: