C ++ - конвертирование long в float или двойное округление значения - PullRequest
1 голос
/ 06 марта 2019

Я хочу конвертировать long в float / double, но приведение округляет значение.Как я могу конвертировать без округления?

Вот мой код:

#include <cmath>
#include <iostream>

int main()
{
    const uint32_t UW = 1000;
    int txPower = 3012916;

    long x = std::stoi("3012916") * UW;
    std::cout << "x = " << x << std::endl;

    auto xFloat = (float)x;
    std::cout << "x float = " << xFloat << std::endl;

    auto xDouble = (double)x;
    std::cout << "xDouble = " << xDouble << std::endl;
    std::cout << "xDouble value cast = " << (double)3012916000 << std::endl;

    return 0;
}

Получает этот вывод:

x = 3012916000                                                                                                                                              
x float = 3.01292e+09                                                                                                                                       
xDouble = 3.01292e+09                                                                                                                                       
xDouble value cast = 3.01292e+09

Помощь!

Ответы [ 2 ]

3 голосов
/ 06 марта 2019

Как уже упоминал Марк Рэнсом в комментариях, вывод, который вы видите, является просто краткой формой для фактического значения, которое хранится в вашем float или double значении.Вы можете увидеть больше цифр, используя, например, std::setprecision(15).

Стандартные значения с плавающей запятой одинарной точности имеют 32 бита, 23 из которых зарезервированы для мантиссы.Предполагается, что наиболее значимый бит мантиссы равен единице (но не сохраняется), когда значение с плавающей запятой не равно нулю.Это означает, что у вас есть 24 бита для хранения, и максимальное значение, которое может хранить мантисса, составляет 2 ^ 24 или 16777216. Как вы можете видеть, вы можете хранить около 7 цифр без потери точности.Я говорю «примерно», потому что не все десятичные представления значения с плавающей запятой могут быть выражены с одинаковой точностью в двоичном формате.

Вот интересный эксперимент:

long n0 = 16777210;
for (int i = 0; i < 10; i++)
{
    long n = n0 + i;
    std::cout << "n=" << n << " / ((float)n)=" << std::setprecision(15) << ((float)n) << std::endl;
}

Вывод:

n=16777210 / ((float)n)=16777210
n=16777211 / ((float)n)=16777211
n=16777212 / ((float)n)=16777212
n=16777213 / ((float)n)=16777213
n=16777214 / ((float)n)=16777214
n=16777215 / ((float)n)=16777215
n=16777216 / ((float)n)=16777216
n=16777217 / ((float)n)=16777216
n=16777218 / ((float)n)=16777218
n=16777219 / ((float)n)=16777220

Число 3012916000 слишком велико, чтобы его можно было хранить точно в значении с плавающей запятой одинарной точности.Когда вы выводите свой номер следующим образом:

std::cout << "x float = " << std::setprecision(15) << xFloat << std::endl;

Тогда получается:

x float = 3012915968

Двойные значения имеют 52 + 1-битную мантиссу, и поэтому ваш номер может быть сохранен точно:

std::cout << "xDouble = " << std::setprecision(15) << xDouble << std::endl;

Выход:

xDouble = 3012916000
0 голосов
/ 06 марта 2019

"Как я могу конвертировать без округления?" Представление целочисленных значений в виде значений с плавающей запятой всегда округляет их из-за их технического представления. Посмотреть здесь Преобразовать int в двойное

...