Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 14, средняя оценка - 4.79
Gepar
1175 / 531 / 20
Регистрация: 01.07.2009
Сообщений: 3,517
#1

Преобразование строки в double - C++

31.07.2011, 16:21. Просмотров 1928. Ответов 10
Метки нет (Все метки)

Собственно есть код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <iomanip>
using namespace std;
 
 
double atof(const char *nPtr)
{
    int factor=1;//множитель (при поиске целого)/делитель(при поиске числа после точки)
    bool point=0;//флаг. True если точка найдена в числе
    int end=0; //последняя цифра в целой части числа (до точки)
    double result=0;
 
    //поиск точки в строке
    for (int i=0;nPtr[i]!='\0';i++)
    {
        end=i;
        if (nPtr[i]=='.')
        {
            point=i;
            end=i-1;
            break;
        }
    }
 
    //перевод числа до точки в double
    for (int i=end;i>=0;i--,factor*=10)
    {
        //если это число
        if (nPtr[i]<=57 && nPtr[i]>=48)
        {
            result+=(nPtr[i]-48)*factor;
        }
        else
         return 0;
    }
 
    //вывести результат преобразования числа до точки
    cout<<"temp result: "<<result<<endl;
 
    //поиск числа после точки
    factor=10;
    if (point && nPtr[point+1]!='\0')
     for (int i=point+1;nPtr[i]!='\0';i++,factor*=10)
     {
        //если это число
        if (nPtr[i]<=57 && nPtr[i]>=48)
        {
            result+=static_cast<double>(nPtr[i]-48)/static_cast<double>(factor);
        }
 
        //если встречается символ не являющийся цифрой - вернуть текущий результат
        else
         return result;
     }
    return result;
}
 
 
int main()
{
    char a[]="123.";
    cout<<atof(a);
}
Проблема возникла с вычислением числа после точки, точнее вычисляется оно не правильно и мне не понятно почему. Вот например в данном примере где у меня число 123, точка здесь есть, но после неё ничего нет значит условие
C++
1
 if (point && nPtr[point+1]!='\0')
не должно сработать так как сл. символ после точки (end указывает на точку) у меня какраз символ конца строки же, хотя на деле это условие выполняется (печать результата внутри функции до выполнения этого условию показывает это) но почему?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
31.07.2011, 16:21
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Преобразование строки в double (C++):

Преобразование типов: строки в double - C++
//Дана строка, состоящая из букв, цифр, запятых, точек, знаков ”+” и ”-”. //Вывести подстроку, которая соответствует записи...

Преобразование строки в long double - C++
Друзья, в Лафоре есть задача номер 7 в главе 7. Её суть: пользователь вводит строку, программа должна считывать только цифры и символ...

Строковые потоки. Преобразование типов (как сделать чтобы из строки число полностью преобразовывалось в double без потери чисел) - C++
Всем привет я перевожу string в double следующим образом double fromString(const std::string&amp; s) { std::istringstream iss(s); ...

Ошибки error C2296: -: недопустимо, левый операнд имеет тип "double (__cdecl *)(double,double,double - C++
Думаю из-за polp #include&lt;iostream&gt; #include&lt;cmath&gt; #include&lt;cstdlib&gt; using namespace std; double polp(double af,double...

Преобразование к double - C++
Есть переменная типа Timestamp. Timestamp определен как структура: struct Timestamp { unsigned int seconds :32; unsigned...

Преобразование из string в double - C++
Вот простой пример демонстрирующий данную проблему: Так работает: #include &lt;iostream&gt; #include &lt;cstdlib&gt; int main() { ...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Евгений М.
1035 / 976 / 54
Регистрация: 28.02.2010
Сообщений: 2,829
Завершенные тесты: 2
31.07.2011, 16:28 #2
Очередной велосипед?
Чем atof из stdlib.h не устроил? Или sscanf (str,"%lf",&result);
?
alex_x_x
бжни
2447 / 1652 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
31.07.2011, 16:33 #3
C
1
2
3
double value;
sscanf( "234.34", "%lf",  &value );
printf( "%lf\n", value );
Gepar
1175 / 531 / 20
Регистрация: 01.07.2009
Сообщений: 3,517
31.07.2011, 16:39  [ТС] #4
Да блин
Евгений М., я же его не просто так назвал atof, это же не случайность, я надеялся Вы догадаетесь. Собственно одно из заданий Дейтела, вот и делаю "свою реализацию".
castaway
Эксперт С++
4881 / 3017 / 370
Регистрация: 10.11.2010
Сообщений: 11,078
Записей в блоге: 10
Завершенные тесты: 1
31.07.2011, 16:43 #5
У тебя переменная point имеет тип bool, а ты присваиваешь ей значение переменной (i) типа int.
Думаю тебе надо определить point как int.
ValeryLaptev
Эксперт С++
1040 / 819 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
31.07.2011, 16:46 #6
Gepar, чтобы такие задачи щелкать, изучи конечные автоматы.
Вот тебе реализация:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
Листинг 5.5. Реализация конечного преобразователя для перевода дробных чисел
// автомат-преобразователь для дробных констант
// функция вычисления цифры
const int notDigit = -1;            // не цифра
int digit(char ch)
{ string digits = "0123456789";
  int d;
  for(d = 0; d < 10; ++d)
    if(ch == digits[d]) return d;
  return notDigit;              // символ - не цифра
}
// функция вычисления класса символа
enum Symbol { D, P, E, S, O, Class };
Symbol type(char ch)
{ if(isdigit(ch)) return D;
  if(ch =='.')    return P;
  if((ch =='e')||(ch=='E')) return E; 
  if((ch =='-')||(ch=='+')) return S;
  return O;
}
// состояния
enum State { start, s1, s2, s3, s4, s5, s6, s7, finish, error }; 
// обработка состояния ошибки
State Error(const char &ch, Number &D) 
{ Error.set();      // установка флага ошибки 
  return error; 
}
// завершение обработки
State Other(const char &ch, Number &D)
{ return finish; }
// в состоянии start – обработка знака
State startS(const char &ch, Number &D)
{ if (ch == '-') D.signN = -1; 
  return s1;    // первая цифра
}
// в состоянии start и s1 – обработка первой цифры
State startD(const char &ch, Number &D) 
{ D.N = digit(ch);
  return s2;    // целая часть
}
// в состоянии s2 – обработка цифр целой части
State intD(const char &ch, Number &D)
{ D.N = D.N * 10 + digit(ch);
  return s2;    // целая часть
}
// в состоянии s2 – обработка точки
State Point(const char &ch, Number &D)
{ return s3; }  // после точки
 
// в состоянии s2 – обработка E
State Exp(const char &ch, Number &D)
{ return s5; }  // после E
// в состоянии s3 – обработка первой цифры после точки
State float1D(const char &ch, Number &D)
{ D.FP = 0.1;  D.F = digit(ch) * D.FP;
  return s4;    // дробная часть
}
// в состоянии s4 – обработка цифр дробной части
State floatD(const char &ch, Number &D) 
{ D.FP/=10; D.F = D.F + digit(ch) * D.FP;
  return s4;    // дробная часть
}
// в состоянии s5 и s6 – обработка первой цифры порядка
State exp1D(const char &ch, Number &D) 
{ D.P = digit(ch);
  return s7;    // порядок     
}
// в состоянии s6 – обработка знака порядка
State expS(const char &ch, Number &D) 
{ if(ch == '-') D.signP = false;
  return s7;    // порядок 
}
// в состоянии s7 – обработка цифр порядка
State expD(const char &ch, Number &D) 
{ D.P = D.P * 10 + digit(ch);
  return s7;    // порядок
}
typedef State (*Action)(const char &ch, Number &D); 
double Double(const string &str)
{ Action matrix[Class][states] =
//start   s1      s2     s3       s4      s5     s6     s7
//перед   после   целая  после    дроб.   после  после  порядок
//числом  знака   часть  точки    часть   Е      знака Е
{{startD, startD, intD,  float1D, floatD, exp1D, exp1D, expD },// цифра 
 {Error,  Error,  Point, Error,   Error,  Error, Error, Error},// точка
 {Error,  Error,  Exp,   Error,   Exp,    Error, Error, Error},// порядок
 {startS, Error,  Error, Error,   Error,  expS,  Error, Error},// знак
 {Error,  Error,  Other, Error,   Other,  Error, Error, Other} // другой 
};
  Number D;
  double result;            // возвращаемый результат
  size_t n = 0;         // индекс символа в строке
  State s = start;          // начальное состояние
  while((s != finish)&&(s != error)&&(n < str.size()))
  { Symbol t = type(str[n]);        // получили класс символа
    s = matrix[t][s](str[n], D);    // вызов функции
    ++n;                // след символ
  }
// проверка состояния при выходе  
  if ((s==s2)||(s==s4)||(s==s7)||   // финишные состояния
      (s==finish))
  { result = D.N+D.F;
    if(!D.signP) D.P = -D.P;
    result = D.signN * result * pow(10.0, D.P);
  }
  else result = 0;
  return result;
}
Для получения цифры преобразователь использует функцию digit(), аналогичную описанной в листинге 5.3.
Обратите внимание на то, что функции Point() и Exp(), обрабатывающие символы точки и экспоненты, фактически не делают ничего, кроме перехода в новое состояние. Это довольно частое явление при разработке конечных преобразователей. Функция отражает некоторое состояние. «Пустые» состояния необходимы для отслеживания правильной последовательности символов во входной строке.

Функция digit()
C++
1
2
3
4
5
6
7
const int noDigit = -1;
int digit(char ch, byte B = 10)
{ string digits = "0123456789";
  int d;                // возвращаемая цифра 
  for(d = 0; d < B; ++d)
    if(ch == digits[d]) return d;
  return noDiget;
Gepar
1175 / 531 / 20
Регистрация: 01.07.2009
Сообщений: 3,517
31.07.2011, 16:55  [ТС] #7
lazybiz, точно, я сначала хотел ставить только 1 если точка найдена, а потом надумал ставить место где эта точка находится. Спасибо, сейчас заменил на int.Теперь работает нормально. Вот бывает так что затупишь и потом не замечаешь.
ValeryLaptev, что-то сложная у Вас на вид реализация, куча состояний и прочего, сейчас попробую разобраться чисто из любопытства. А вообще: можно за ухом и ногой почесать, но зачем же так усложнять?
ValeryLaptev
Эксперт С++
1040 / 819 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
31.07.2011, 16:58 #8
Gepar, это реализация конечного автомата - НЕ минимального. Каждое состояние - функция. Это чтобы не писать длинный переключатель. Идея данного подхода - у Герба Саттера.
alex_x_x
бжни
2447 / 1652 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
31.07.2011, 17:47 #9
видов записей вещественных чисел много, вот набрасал вариант на основе конечных автоматов

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <cstdlib>
#include <iostream>
#include <cassert>
 
#define DEBUG
 
void add_digit( unsigned& value, unsigned digit )
{
   value = value * 10 + digit;
}
 
double _atof( const char* str )
{
  enum { 
        START, 
        WAIT_NUM_POINT_OR_END,
        WAIT_NUM_AFTER_POINT,
        WAIT_NOT_NUM,
        FINISH,
        ERROR
       } state;   
   
   enum {
        NUMBER,
        POINT,
        NOT_NUMBER
        } value;     
   
   char c;
   size_t pos = 0;
   unsigned number = 0;
   unsigned up = 0, down = 0, degree = 1;  
         
   state = START; 
  
   while ( state != FINISH && state != ERROR )
   {
      c = str[pos];
      if( c >= '0' && c<='9' )
      {
         number = c - '0';
         value = NUMBER; 
         // std::cout << "NUMBER " << number << std::endl; 
      }   
      else
      {
         value = ( c == '.' ? POINT : NOT_NUMBER );
         // std::cout << ( value == POINT ?
         //             "POINT" : "NOT_POINT" )
         //           << std::endl; 
      }    
      // std::cout << '(' << state << ')' << std::endl;
      switch( state )
      {
         case START:
           if( value == NUMBER )
           {
              state = WAIT_NUM_POINT_OR_END;
              add_digit( up, number ); 
           }
           else if( value == POINT )
           {
              state = WAIT_NUM_AFTER_POINT;
           }       
           else
           {
              state = ERROR;
           }    
           break;
         case WAIT_NUM_POINT_OR_END:
           if( value == NUMBER )
           {
              state = WAIT_NUM_POINT_OR_END;  
              add_digit( up, number ); 
           }
           else if( value == POINT )
           { 
              state = WAIT_NOT_NUM; 
           }          
           else
           {
              state = FINISH;
           }   
           break; 
         case WAIT_NUM_AFTER_POINT:
           if( value == NUMBER )
           {
              state = WAIT_NOT_NUM;
              add_digit( down, number ); 
              degree *= 10; 
           }
           else
           {
              state = ERROR;
           }
           break;   
         case WAIT_NOT_NUM:
           if( value != NUMBER )
           {
              // std::cout << "FINISH" << std::endl; 
              state = FINISH;
           } 
           else
           {
              add_digit( down, number ); 
              degree *= 10; 
           }              
           break;
         default:
           assert( 0 );  
      }   
      
      ++pos; 
   }    
   
   if( state == FINISH )
   {
      // std::cout << up << '.' << down << std::endl;
      return static_cast<double>(up) +
             static_cast<double>(down) / degree;   
   }
#ifdef DEBUG      
   else
   {
      std::cout << "error" << std::endl;
   }  
#endif
   return 0;
}
 
int main()
{
  const char* szTest[] = { 
                          "123.12",
                          "123", 
                          "0.234",
                          ".34",
                          "sdf",
                          ".23d",
                          ".sd",
                          "1."    
                          };
                         
  for( size_t i=0;i<sizeof( szTest )/sizeof( szTest[0] );++i )
  {
     std::cout << _atof( szTest[i] ) << std::endl;
  }    
       
}
Bash
1
2
3
4
5
6
7
8
9
10
123.12
123
0.234
0.34
error
0
0.23
error
0
1
http://liveworkspace.org/code/0c939a...1efcb707d6ec77

Добавлено через 1 минуту
хотя вижу уже есть вариант на таблицах =)
castaway
Эксперт С++
4881 / 3017 / 370
Регистрация: 10.11.2010
Сообщений: 11,078
Записей в блоге: 10
Завершенные тесты: 1
31.07.2011, 18:13 #10
ValeryLaptev, что это:
C++
1
2
3
4
5
6
7
const int noDigit = -1;
int digit(char ch, byte B = 10)
{ string digits = "0123456789";
  int d;                                // возвращаемая цифра 
  for(d = 0; d < B; ++d)
    if(ch == digits[d]) return d;
  return noDiget;
??!

Так не проще?
C++
1
#define    DIGIT( ch )    ((ch) - '0')
ValeryLaptev
Эксперт С++
1040 / 819 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
31.07.2011, 18:15 #11
lazybiz, у меня там функция была, которая в любой системе до 16 выдавала цифру - я ее просто обрезал.
Макросы, конечно можно написать, но этот всегда чревато при развитии проекта.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
31.07.2011, 18:15
Привет! Вот еще темы с ответами:

Преобразование из AnsiString в Double - C++
Делаю калькулятор. Преобразую AnsiString в Double if(p=='+') all=all+atof(Form1-&gt;Edit1-&gt;Text.c_str()); Вывожу в Edit Exit-&gt;Text=all; ...

Преобразование из double в строку - C++
Здравствуйте, в общем такое дело, есть winapi приложение с подключаемой .dll, при подсчёте функция должна вывести в эдит дробный...

Преобразование Double в string - C++
Допустим у меня есть число double n = 0.0000000000 мне нужно преобразовать его в строку string s = 0.0000000000. Как это сделать?

Преобразование из string в double - C++
Объясните пожалуйста в чем связь между преобразованием данный из string в double и библиотекой русского языка Вот так работает #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
31.07.2011, 18:15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru