Подтвердить что ты не робот

C/С++ подсчитывает число десятичных знаков?

Предположим, что ввод от пользователя является десятичным числом, например. 5. 2155 (с 4 десятичными цифрами). Он может храниться свободно (int, double) и т.д.

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

4b9b3361

Ответ 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. Таким образом, у вас есть конечная точность. Недостатком этого является то, что вам нужно написать методы для арифметических операций (+, -, *,/и т.д.), Но вы можете легко перезаписать операторы в С++. Я знаю, что это отклоняется от вашего первоначального вопроса, но всегда лучше хранить ваши десятичные знаки в конечной форме. Таким образом, вы также можете ответить на вопрос о том, сколько десятичных чисел у числа.