Обнаружение отрицательного 0, хранящегося как двойной в C ++ - PullRequest
19 голосов
/ 01 апреля 2011

Я делаю некоторые математические вычисления (пытаюсь преобразовать код Matlab в C ++, используя VS2010), и мне нужно иметь возможность сказать, получаю ли я в какой-то момент отрицательный 0.

Согласно стандарту IEEE-0 / + 0 отличаются только знаковым битом (остальные 0).

Я использовал следующий фрагмент кода ( post ), чтобы интерпретировать свой дубль как беззнаковый символ

double f = -5;
    unsigned char *c = reinterpret_cast<unsigned char *>(&f);
    for(int i=(sizeof(double)-1); i>=0; i--){
        printf("%02X", c[i]);
   }

При попытке с 5 / -5 я получаюожидаемый результат:

C014000000000000 (-5)
4014000000000000 (5)

Но когда я пробую это с 0 / -0, я получаю только нули в обоих случаях.VS2010 заявляет, что они соответствуют IEEE ( msdn ), поэтому я не уверен, какую часть я не получу.

Если 0 / -0 действительно хранятся в памяти точно таким же образом, я никак не могу отличить их, если мне нужно, чтобы я прекратил тратить свое время :) Верно?

Ответы [ 3 ]

24 голосов
/ 01 апреля 2011

Если вы напишите

double d = -0; 

произойдет следующее:

Во-первых, будет оцениваться -0, который имеет тип int, потому что 0 имеет тип int. Результат будет 0. Тогда 0 будет преобразован в удвоенный и назначен таким образом +0,0, а не -0,0

double d = -0.0; // is your solution.
18 голосов
/ 02 апреля 2011

В дополнение к хорошему ответу Армена, вы должны использовать signbit для обнаружения этого. Это защитит вас от проблем с порядком байтов:

#include <iostream>
#include <cmath>

int main()
{
    std::cout << std::signbit(0.0) << '\n';
    std::cout << std::signbit(-0.0) << '\n';
}

0
1
0 голосов
/ 03 апреля 2014

Функция такого же типа переписана в более короткую форму:

static inline unsigned bool signbit(double& d)
{
    return ( ((unsigned char*)&d)[sizeof(double)-1] & 0x80) != 0;
}


int EstimateDoubleBufferSize( double& d )
{
    int len = 0;

    if( signbit(d) ) //if ( d < 0 )
    {
        d = -d;
        len++;
    }
    d += 0.0000005;

    int m = (int) log10(d);

    if( m < 0 )
        m = 1;  // 0.xxxx - include 0
    else
        m++;    // Include first character

    len += m + 1 /*dot*/ + 6 /* precision after . */;
    return len;
}

Также мне нужно было выяснить размер sprintf для компилятора Microsoft C ++ - для этого также предусмотрена функция.

...