Вопрос по c, c++ – C / C ++ считая количество десятичных знаков?

16

Допустим, что ввод от пользователя является десятичным числом, напр. 5.2155 (имеющий 4 десятичных знака). Может храниться свободно (int, double) и т. Д.

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

Не могли бы вы уточнить, "сколько десятичных знаков в числе" & quot ;? Вы имеете в виду, сколько десятичных цифр в дробной части числа? Doug
Да, ваше предположение верно. Milan

Ваш Ответ

11   ответов
1

Спустя годы после боя, но я сделал свое собственное решение в трех линиях:

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

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

6

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

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

Если вы не можете сделать это (case B), то вам нужно сделать предположение о максимальном количестве десятичных знаков, преобразовать число обратно в строковое представление и округлить до этого максимального числа, используяметод округления к четному, Например, если пользователь вводит 1.1, которое представляется как 1.09999999999999 (гипотетически), преобразуя его обратно в строковые значения, угадайте, что, & quot; 1.09999999999999 & quot ;. Округляя это число, скажем, до четырех десятичных знаков, вы получите «1.1000». Теперь он вернулся кcase A.

18

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

Во-первых, это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:
@Guillaume, да, поздравляю с тем, что был первым, кто обнаружил эту ошибку в четырехyears. Исправлено в соответствии с вашим предложением.
Я бы назвал умным только из-за того, как тщательно вы ответили на вопрос.
.2155 не станет .21559999999999, но .2156 может
& APOS не должен; тwhile abs(num) <= 0.0000001: бытьwhile abs(num) >= 0.0000001: ?
Никто не любит smart-alec :-) Спасибо, @quant_dev, я исправил это.
0
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);
    }
Добро пожаловать в переполнение стека! Пожалуйста, не отвечайте только с исходным кодом. Попробуйте дать хорошее описание того, как работает ваше решение. Увидеть:How do I write a good answer?, Спасибо
-1

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

atof(string.c_str());

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

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

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

#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]

0

Вот полная программа

 #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); 
 }
Пожалуйста, объясните, как это решает проблему OP, а не просто почтовый индекс.
2

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

0

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

4

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

начать с дробной части: .2155

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

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

4 шага = 4 десятичных знака

Это дает вам ошибки округления очень легко. Попытайся.
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();
Вам каким-то образом необходимо учитывать числа, которые не вписываются в число с плавающей точкой, т. Е. Если вы в конечном итоге наберете 5.215399999999999, вы, вероятно, захотите сообщить о 4 десятичных знаках.

Похожие вопросы