сдвиг вправо двоичного представления числа с плавающей запятой -0.0 - PullRequest
0 голосов
/ 16 мая 2019

Я делаю программу для проверки знака двойного числа / числа с плавающей запятой, сначала я преобразую указатель числа в длинное целое, затем я проверяю бит знака, если он равен 0 или 1. Я неВы поймете, почему печать бита знака с этой операцией * указатель >> 63 равен -1 вместо 1?:

    double d = -0.0;
    int64_t *pointer = (int64_t *) &d;
    if (*pointer >> 63)
       printf("negative number\n");
    else
       printf("positive number\n");
    // if i print the result of (*pointer >> 63), it gives me -1
    // so how can this go inside my if condition?

Кстати, двоичная печать -0.0 в 64 битах дает мне 100000000 ... 000

Ответы [ 3 ]

3 голосов
/ 16 мая 2019

Это трудно сделать в полной общности из-за существования нулей со знаком в типах с плавающей запятой и возможности дополнения до 1 целыми типами.

Помимо неопределенности (int64_t*)&d (к которой можно обратиться с помощью union type-pun), этот подход вернет неправильный знак для -0.0.

К счастью, вы можете использовать signbit() из math.h, который, вероятно, реализует функцию непереносимым способом.

0 голосов
/ 16 мая 2019

так, как это может войти в мое условие if?

1 Использование signbit(d)

if (signbit(d)) {
  puts("Negative");
}

или

2 Используйте составной литерал и union.

//  v--------------------------------------------v  compound literal
if ((union { double dd; int64_t i64; }){ .dd = d }.i64 < 0) {
  puts("Negative");
}

Этот подход должен иметь ожидаемый размер и кодирование double с битом знака в том же месте, что и int64_t.

// Test size
_Static_assert(sizeof(int64_t) == sizeof(double), "Mis-match size");
0 голосов
/ 16 мая 2019

Во-первых, смещение вправо отрицательного целого числа определяется реализацией. Следующая разыменование указателя типа, отличного от фактического типа, является явно неопределенным поведением из-за строгого правила псевдонимов (Google для него, если вы его не знаете).

Если вы хотите, чтобы ваш код был переносимым, единственный надежный способ - использовать memcpy для передачи представления значения. Это только предполагает, что:

  • sizeof(double) совпадает с sizeof(uint64_t):
  • знаковый бит - это бит63 uint64_t с таким представлением

Код:

double d = -0.0;
uint64_t u;

memcpy(&u, &d, sizeof(u));

print("Sign bit in that architecture %d\n", u>>63); 
...