2014-01-12 3 views
0

Мне нужно проверить количество десятичных знаков в номере с плавающей запятой для моей задачи, для проверки ввода, как я могу это сделать?Как подсчитать количество десятичных знаков в float в C++?

+2

Переменные с плавающей запятой не имеют десятичных знаков. У них есть бинарные места. – EJP

+0

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

ответ

0
int decimals_float (float number){ 
    float num = number;  // local variable to hold the number 
    int count = 0;   // variable to count the decimals 
    num = abs(num);   // take the absolute value of the number (no negatives) 
    num = num - (int)num;  // take off the digit and leave only decimals in the number 
    while(num >= 0.1){  // checking until >= 0.1, because if we use != or >= 0 it might not work 
     num *= 10;   // multiply the number by 10, to remove one decimal 
     count++;    // add one to the decimals 
     num -= (int)num;  // take off the digit and leave only decimals in the number 
    } 
    return count;    // return amount of decimals 
} 
+2

decimals_float (0.09) == 0 –

+0

@DavidHeffernan На самом деле, мой плохой. Я не должен был делать '> = 0,1', вместо этого я должен был бы сделать'> = 0.0000001', я думаю. – user3182683

+0

Предупреждение: компилируется без предупреждений, но ведет себя совершенно неправильно, если вы только включаете '' для декларации для 'abs'. Ой с моей стороны. :) – hvd

4

Вы не можете этого сделать, потому что поплавок хранится в двоичной с плавающей запятой, а не в десятичной системе. Так, например, 0,1 не может быть точно представлено в двоичной переменной с плавающей запятой. И если вы не можете точно указать число, то вы не можете рассуждать о его представлении.

Если вы хотите представить число как десятичное, то вы должны использовать десятичное представление, а не двоичное представление.

Необходимое чтение по этой теме: What Every Computer Scientist Should Know About Floating-Point Arithmetic

+1

На самом деле, если значение, хранящееся в двоичной плавающей запятой типа 'F', имеет меньше, чем' std :: numeric_limits :: digits10' цифр, точное десятичное значение может быть восстановлено, например, с помощью Steele & White's Dragon4. Вы просто считаете цифры там. По общему признанию, вы потеряете счетчик завершающих нулей, поскольку двоичные плавающие точки будут нормализованы. –

+1

@ DietmarKühl Вы можете определить конверсии в оба конца. Однако неясно, что именно об этом спрашивают. Для меня вопрос на самом деле показывает незнание представлений с плавающей запятой, и ответ Дэвида отвечает на это лучше всего (ИМХО). Все, что отсутствует, это ссылка на «Все, что вы хотели знать о плавающей запятой». –

+0

@James Это сейчас! –

1

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

#include <cmath> 
template< class T > 
unsigned NumberOfDecimalPlaces(const T& num, const unsigned maxNumberOfDecimalPlacesReturned, const T& threshold = 1e-12) 
{ 
    static_assert(std::is_floating_point<T>::value, 
    "NumberOfDecimalPlaces if for floating point numbers only"); 

    T number = std::abs(num); 
    unsigned numDecimalPlaces = 0; 
    while((number - std::floor(number)) > threshold && 
     (std::ceil(number) - number) > threshold) 
    { 
    if(++numDecimalPlaces >= maxNumberOfDecimalPlacesReturned) 
     break; 
    number *= 10.0; 
    } 
    return numDecimalPlaces; 
} 

несколько тестов:

TEST(NumberOfDecimalPlaces_Is_0_For_0) 
{ 
    CHECK_EQUAL(0u, NumberOfDecimalPlaces(0.0, 20)); 
} 

TEST(NumberOfDecimalPlaces_Yields_Max) 
{ 
    CHECK_EQUAL(5u, NumberOfDecimalPlaces(0.11121212, 5)); 
    CHECK_EQUAL(5u, NumberOfDecimalPlaces(0.00000001, 5)); 
} 

TEST(NumberOfDecimalPlaces_WorksOk_ForPrettyNormalNumbers) 
{ 
    CHECK_EQUAL(1u, NumberOfDecimalPlaces(0.1, 20)); 
    CHECK_EQUAL(1u, NumberOfDecimalPlaces(0.8, 20)); 
    CHECK_EQUAL(8u, NumberOfDecimalPlaces(0.11121212, 20)); 
    CHECK_EQUAL(8u, NumberOfDecimalPlaces(0.00000001, 20)); 
    CHECK_EQUAL(7u, NumberOfDecimalPlaces(0.0000001, 20)); 

    //this is represented as 0.0000000109999999 
    CHECK_EQUAL(9u, NumberOfDecimalPlaces(0.000000011, 20)); 
} 
+1

Как это работает для PI? или 1/3? –

+0

должен возвращать maxNumberOfDecimalPlacesReturned – stijn

+0

Можно ли переписать его на простые функции, потому что я еще не знаю шаблонов? – user3182683

1

вопрос, как правило, является «Сколько цифр (точность) мне нужно?».

Давайте возьмем две фракции, 1/10 и 22/7.

С 1/10, который оценивается в 0,1, действительно ли существует только одна цифра после десятичной точки или равно 0.1000. Найдите в Интернете «Значимые цифры».

С долей 22/7, сколько цифр после десятичной точки?
С иррациональными числами может быть последовательность, которая повторяется или нет. Например, 1/3, повторяется после первого десятичного знака. Однако значение для PI не повторяется?

Или вы запрашиваете количество цифр до десятичной точки? На это можно ответить, используя функции log. number of digits before decimal point = log(number)/log(10);

4

Подтверждение ввода должно быть выполнено, когда у вас есть вход. Вы должны изучить текст ввода и решить, приемлемо это или нет.

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

+0

+1 Любой отчет об ошибке должен содержать ** точный ** текст, который отклоняется, включая начальные и конечные нули, которые неизбежно теряются при преобразовании. –

Смежные вопросы