2009-07-05 2 views
13

Допустим, что ввод от пользователя - десятичное число, например. 5. (с 4 десятичными цифрами). Он может храниться свободно (int, double) и т. Д.C/C++ подсчет числа десятичных знаков?

Есть ли умный (или очень простой) способ узнать, сколько десятичных чисел у них есть? (вроде как вопрос, как вы находите, что число четное или нечетное, маскируя последний бит).

+0

Можете ли вы пояснить, «сколько десятичных чисел у числа»? Вы имеете в виду, сколько десятичных цифр находится в дробной части числа? – Doug

+0

Да, ваше предположение верно. – Milan

ответ

15

Два пути я знаю, ни очень умна, к сожалению, но это скорее ограничение окружающей среды, а не меня :-)

Первый находится в sprintf номер в большой буфер с помощью строки формата "%.50f", отделяйте конечные нули, затем подсчитывайте символы после десятичной точки. Это будет ограничено самим семейством printf. Или вы можете использовать строку в качестве входных данных пользователя (а не sprintf с плавающей точкой), чтобы избежать проблем с плавающей запятой в целом.

Второй заключается в том, чтобы вычесть целочисленную часть, затем итеративно умножить на 10 и снова вычесть целочисленную часть, пока не получите нуль. Это ограничивается пределами компьютерного представления чисел с плавающей запятой - на каждом этапе вы можете получить проблему числа, которое невозможно представить точно (так .2155 может быть фактически .215499999998). Что-то вроде следующего (непроверенные, за исключением того, в моей голове, что примерно на одном уровне с COMX-35):

count = 0 
num = abs(num) 
num = num - int(num) 
while num != 0: 
    num = num * 10 
    count = count + 1 
    num = num - int(num) 

Если вы знаете, то цифры, которые вы будете получать (например, все они будут От 0 до 4 цифр после десятичной точки), вы можете использовать стандартные «трюки» с плавающей запятой, чтобы сделать это правильно. Например, вместо:

while num != 0: 

использования

while abs(num) >= 0.0000001: 
+1

.2155 не собирается становиться .21559999999999, но .2156 может –

+1

Никто не любит smart-alec :-) Спасибо, @quant_dev, я исправил его. – paxdiablo

+2

Я бы квалифицировал как умный только из-за того, насколько тщательно вы ответили на вопрос. – ojblass

4

Off верхней части моей головы:

начала с дробной частью: 0,2155

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

.2155 * 10 = 2.155 
.155 * 10 = 1.55 
.55 * 10 = 5.5 
.5 * 10 = 5.0 

4 шага = 4 десятичных цифр

+0

Это дает вам ошибки округления очень легко. Попробуй. – Bim

2

Что вы имеете в виду «хранятся свободно (интермедиат» После того, как хранится в междунар, он имеет нулевой десятичные слева, очевидно, двойная хранится. в двоичной форме, поэтому нет очевидного или простого отношения к «десятичным знакам». Почему бы вам не сохранить ввод как строку, достаточно длинную, чтобы считать эти десятичные числа, прежде чем отправлять ее в конечный конечный пункт числовой переменной?

2

Возможно, что-то подобное:

float i = 5.2154; 
std::string s; 
std::string t; 
std::stringstream out; 
out << i; 
s = out.str(); 

t = s.substr(s.find(".")+1); 
cout<<"number of decimal places: " << t.length(); 
+0

Вам нужно каким-то образом учитывать числа, которые не соответствуют аккуратно в поплавок, то есть если вы в итоге получите 5.2153999999999999, вы, вероятно, захотите сообщить 4 десятичных знака. –

6

Как только число преобразуется из представления пользователя (строка, файл OCR-ed gif, что бы то ни было) в число с плавающей запятой, вы не имеете дело с одинаковым номером обязательно. Поэтому строгий, не очень полезный ответ - «Нет».

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

Если вы не можете это сделать (случая B), то вам необходимо сделать предположение о максимальном количестве знаков после запятой, конвертировать число обратно в строковое представление и вокруг него к этому максимальному числу с помощью round-to-even method. Например, если пользователь поставляет 1.1, который представляется как 1.09999999999999 (гипотетически), преобразовывая его обратно в вывод строки, угадайте, что «1.09999999999999». Округление этого числа, скажем, на четыре десятичные точки дает вам «1.1000». Теперь он вернулся к кейс A.

0

Я бы предложил прочитать значение как строку, найти десятичную точку и проанализировать текст до и после него как целые числа. Нет ошибок с плавающей запятой или округлением.

-1

Один из способов - прочитать число в виде строки. Найдите длину подстроки после десятичной точки, и сколько десятичных знаков введено человеком. Для того, чтобы преобразовать эту строку в число с плавающей точкой, используя

На другой ноте; это всегда хорошая идея при работе с операциями с плавающей запятой, чтобы хранить их в специальном объекте с конечной точностью. Например, вы можете хранить точки с плавающей точкой в ​​специальном типе объекта под названием «Десятичный», где целая часть числа и десятичная часть номера являются значениями int. Таким образом, у вас есть конечная точность. Недостатком этого является то, что вам нужно написать методы для арифметических операций (+, -, *,/и т. Д.), Но вы можете легко перезаписать операторы в C++. Я знаю, что это отклоняется от вашего первоначального вопроса, но всегда лучше хранить ваши десятичные знаки в конечной форме. Таким образом, вы также можете ответить на вопрос о том, сколько десятичных чисел у числа.

+0

Это (почти) никогда не бывает хорошим, если вам нужно быстро вычислить что-либо. –

1

с использованием формата Scientific Notation (чтобы избежать ошибок округления):

#include <stdio.h> 
#include <string.h> 

/* Counting the number of decimals 
* 
* 1. Use Scientific Notation format 
* 2. Convert it to a string 
* 3. Tokenize it on the exp sign, discard the base part 
* 4. convert the second token back to number 
*/ 

int main(){ 

    int counts; 
    char *sign; 
    char str[15]; 
    char *base; 
    char *exp10; 
    float real = 0.00001; 

    sprintf (str, "%E", real); 
    sign= (strpbrk (str, "+"))? "+" : "-"; 

    base = strtok (str, sign); 
    exp10 = strtok (NULL, sign); 

    counts=atoi(exp10); 

    printf("[%d]\n", counts); 

    return 0; 
} 

[5]

1

лет после боя, но как я сделал свое собственное решение в три строки:

string number = "543.014";  
size_t dotFound; 
stoi(number, &dotFound)); 
string(number).substr(dotFound).size() 

Конечно, вы должны предварительно протестировать, если это действительно поплавок (с stof(number) == stoi(number) например)