Обрезать десятичное значение в C ++ - PullRequest
8 голосов
/ 20 ноября 2008

Какой самый простой способ обрезать переменную C ++ float со значением от 0,6000002 до значения 0,6000 и сохранить ее обратно в переменной?

Ответы [ 9 ]

12 голосов
/ 20 ноября 2008

Хорошую справку по , почему это происходит, можно найти в Что должен знать каждый компьютерный специалист об арифметике с плавающей точкой Дэвида Голдберга.

7 голосов
/ 20 ноября 2008

Во-первых, важно знать, что числа с плавающей запятой аппроксимируются. Посмотрите ссылку, предоставленную @Greg Hewgill, чтобы понять, почему эта проблема не полностью решаема.

Но вот пара решений проблемы, которые, вероятно, удовлетворят ваши потребности:

Возможно, лучший метод, но менее эффективный:

char sz[64];
double lf = 0.600000002;
sprintf(sz, "%.4lf\n", lf); //sz contains 0.6000

double lf2 = atof(sz);

//lf == 0.600000002;
//lf2 == 0.6000

printf("%.4lf", lf2); //print 0.6000

Более эффективный способ, но, вероятно, менее точный:

double lf = 0.600000002;
int iSigned = lf > 0? 1: -1;
unsigned int uiTemp = (lf*pow(10, 4)) * iSigned; //Note I'm using unsigned int so that I can increase the precision of the truncate
lf = (((double)uiTemp)/pow(10,4) * iSigned);
6 голосов
/ 20 ноября 2008

Реально это невозможно. Это не ограничение C ++, а способ работы с плавающей запятой. Для многих значений нет точных представлений, поэтому вы не можете просто усечь их до определенного количества цифр.

Вы можете усечь при печати с использованием строк формата printf.

Если вам действительно нужно хранить только ограниченное количество цифр, я предлагаю вместо этого использовать тип данных с фиксированной точностью.

3 голосов
/ 20 ноября 2008

я думаю, что вопрос, который следует задать здесь: Зачем тебе это урезать?

Если это для сравнения значений, возможно, вам следует рассмотреть возможность использования теста epsilon. (с дополнительным значением допуска, в вашем случае, так как оно кажется намного большим, чем общепринятый эпсилон)

Если вы просто хотите распечатать его как 0,6000, используйте методы, предложенные другими.

1 голос
/ 28 апреля 2017

Для C ++ 11 вы можете использовать std::round, определенный в заголовке <cmath>:

auto trunc_value = std::round(value_to_trunc * 10000) / 10000;
1 голос
/ 07 февраля 2010

Используйте это:

floor(0.6000002*10000)/10000
1 голос
/ 23 ноября 2008
roundf(myfloat * powf(10, numDigits)) / powf(10, numDigits);

Например, в вашем случае вы усекаете три цифры (numDigits). Вы бы использовали:

roundf(0.6000002 * 1000) / 1000
// And thus:
roundf(600.0002) / 1000
600 / 1000
0.6

(Вы, вероятно, где-то сохраните результат powf, поскольку вы используете его дважды.)

Из-за того, как поплавки обычно хранятся на компьютерах, вероятно, будут неточности. Это то, что вы получаете за использование поплавков.

0 голосов
/ 20 января 2016

Подобно другим ответам, НО вы не должны забывать, что round, floor и trunc по определению различны См. Определение и пример вывода следующего:

http://www.cplusplus.com/reference/cmath/trunc/

В этом случае нам нужно переворачивать с точностью до 4 десятичных знаков и избавляться от незначащих десятичных:

trunc(valueToTrunc*10000)/10000

или

value = (double)((int)(valueToTrunc*10000))/(double)10000
0 голосов
/ 14 марта 2013

Вот функция, использующая рекомендации в других ответах и ​​пример ее использования:

#include <iostream>
#include <cmath>

static void Truncate(double& d, unsigned int numberOfDecimalsToKeep);

int main(int, char*[])
{

  double a = 1.23456789;
  unsigned int numDigits = 3;

  std::cout << a << std::endl;

  Truncate(a,3);

  std::cout << a << std::endl;

  return 0;
}

void Truncate(double& d, unsigned int numberOfDecimalsToKeep)
{
    d = roundf(d * powf(10, numberOfDecimalsToKeep)) / powf(10, numberOfDecimalsToKeep);
}
...