C/С++ подсчитывает число десятичных знаков?
Предположим, что ввод от пользователя является десятичным числом, например. 5. 2155 (с 4 десятичными цифрами). Он может храниться свободно (int, double) и т.д.
Есть ли умный (или очень простой) способ узнать, сколько десятичных чисел у числа? (вроде как вопрос, как вы находите, что число четное или нечетное, маскируя последний бит).
Ответы
Ответ 1
Два способа, о которых я знаю, не очень умный, но это скорее ограничение среды, чем меня: -)
Во-первых, 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:
Ответ 2
Как только число преобразуется из представления пользователя (строка, OCR-ed gif файл, что угодно) в число с плавающей запятой, вы не имеете дело с одинаковым номером обязательно. Поэтому строгий, не очень полезный ответ - "Нет".
Если (case A), вы можете избежать преобразования числа из строкового представления, проблема становится намного проще, вам нужно только подсчитать цифры после десятичной точки и вычесть количество конечных нулей.
Если вы не можете этого сделать (case B), вам нужно сделать предположение о максимальном количестве десятичных знаков, преобразовать число обратно в строковое представление и округлить его до этого максимального числа, используя метод round-to-even. Например, если пользователь поставляет 1.1, который представляется как 1.09999999999999 (гипотетически), преобразовывая его обратно в вывод строки, угадайте, что "1.09999999999999". Округление этого числа, скажем, на четыре десятичные точки дает вам "1.1000". Теперь он возвращается к случаю A.
Ответ 3
Сверху моей головы:
начните с дробной части:.2155
многократно умножьте на 10 и выбросите целую часть числа, пока не получите нуль. Количество шагов будет числом десятичных знаков. например:
.2155 * 10 = 2.155
.155 * 10 = 1.55
.55 * 10 = 5.5
.5 * 10 = 5.0
4 шага = 4 десятичные цифры
Ответ 4
Что значит "хранится свободно" (int "?" После того, как он хранится в int, он имеет нулевые десятичные знаки слева, очевидно. Двойной хранится в двоичной форме, поэтому нет очевидного или простого отношения к "десятичным знакам". вы не держите ввод как строку, достаточно длинную, чтобы считать эти десятичные числа, прежде чем отправлять его в конечный пункт назначения числовой переменной?
Ответ 5
Что-то вроде этого может работать:
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();
Ответ 6
используя формат 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]
Ответ 7
Спустя годы после боя, но поскольку я сделал свое решение в трех строках:
string number = "543.014";
size_t dotFound;
stoi(number, &dotFound));
string(number).substr(dotFound).size()
Конечно, вы должны сначала протестировать, если это действительно поплавок
(Например, stof(number) == stoi(number)
)
Ответ 8
Я бы предложил прочитать значение в виде строки, найти десятичную точку и проанализировать текст до и после него как целые числа. Нет ошибок с плавающей запятой или округлением.
Ответ 9
char* fractpart(double f)
{
int intary={1,2,3,4,5,6,7,8,9,0};
char charary={'1','2','3','4','5','6','7','8','9','0'};
int count=0,x,y;
f=f-(int)f;
while(f<=1)
{
f=f*10;
for(y=0;y<10;y++)
{
if((int)f==intary[y])
{
chrstr[count]=charary[y];
break;
}
}
f=f-(int)f;
if(f<=0.01 || count==4)
break;
if(f<0)
f=-f;
count++;
}
return(chrstr);
}
Ответ 10
Вот полная программа
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <math.h>
char charary[10]={'1','2','3','4','5','6','7','8','9','0'};
int intary[10]={1,2,3,4,5,6,7,8,9,0};
char* intpart(double);
char* fractpart(double);
int main()
{
clrscr();
int count = 0;
double d = 0;
char intstr[10], fractstr[10];
cout<<"Enter a number";
cin>>d;
strcpy(intstr,intpart(d));
strcpy(fractstr,fractpart(d));
cout<<intstr<<'.'<<fractstr;
getche();
return(0);
}
char* intpart(double f)
{
char retstr[10];
int x,y,z,count1=0;
x=(int)f;
while(x>=1)
{
z=x%10;
for(y=0;y<10;y++)
{
if(z==intary[y])
{
chrstr[count1]=charary[y];
break;
}
}
x=x/10;
count1++;
}
for(x=0,y=strlen(chrstr)-1;y>=0;y--,x++)
retstr[x]=chrstr[y];
retstr[x]='\0';
return(retstr);
}
char* fractpart(double f)
{
int count=0,x,y;
f=f-(int)f;
while(f<=1)
{
f=f*10;
for(y=0;y<10;y++)
{
if((int)f==intary[y])
{
chrstr[count]=charary[y];
break;
}
}
f=f-(int)f;
if(f<=0.01 || count==4)
break;
if(f<0)
f=-f;
count++;
}
return(chrstr);
}
Ответ 11
Так как цель состоит в том, чтобы быть быстрым, это улучшение по Андрею Александру. Его версия была уже быстрее, чем наивный способ (деление на 10 на каждую цифру). Приведенная ниже версия имеет постоянное время и быстрее, по крайней мере, для x86-64 и ARM для всех размеров, но занимает в два раза больше двоичного кода, поэтому она не так удобна для кэша.
Тесты для этой версии против alexandrescu версии на моем PR на фоллике в facebook.
Работает на unsigned
, не signed
.
inline uint32_t digits10(uint64_t v) {
return 1
+ (std::uint32_t)(v>=10)
+ (std::uint32_t)(v>=100)
+ (std::uint32_t)(v>=1000)
+ (std::uint32_t)(v>=10000)
+ (std::uint32_t)(v>=100000)
+ (std::uint32_t)(v>=1000000)
+ (std::uint32_t)(v>=10000000)
+ (std::uint32_t)(v>=100000000)
+ (std::uint32_t)(v>=1000000000)
+ (std::uint32_t)(v>=10000000000ull)
+ (std::uint32_t)(v>=100000000000ull)
+ (std::uint32_t)(v>=1000000000000ull)
+ (std::uint32_t)(v>=10000000000000ull)
+ (std::uint32_t)(v>=100000000000000ull)
+ (std::uint32_t)(v>=1000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000ull)
+ (std::uint32_t)(v>=100000000000000000ull)
+ (std::uint32_t)(v>=1000000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000000ull);
}
Ответ 12
Один из способов - прочитать число в виде строки. Найдите длину подстроки после десятичной точки и количество десятичных знаков, введенных человеком. Чтобы преобразовать эту строку в float с помощью
atof(string.c_str());
В другом примечании; это всегда хорошая идея при работе с операциями с плавающей запятой, чтобы хранить их в специальном объекте с конечной точностью. Например, вы можете хранить точки с плавающей точкой в специальном типе объекта под названием "Десятичный", где целая часть числа и десятичная часть номера являются значениями int. Таким образом, у вас есть конечная точность. Недостатком этого является то, что вам нужно написать методы для арифметических операций (+, -, *,/и т.д.), Но вы можете легко перезаписать операторы в С++. Я знаю, что это отклоняется от вашего первоначального вопроса, но всегда лучше хранить ваши десятичные знаки в конечной форме. Таким образом, вы также можете ответить на вопрос о том, сколько десятичных чисел у числа.