Приведение типа потом вычитание
От: Igore Россия  
Дата: 03.05.05 14:20
Оценка:
Что-то я не могу понять почему это неправильно работает.

Private Sub Form_Load()
   Dim q1 As Double
   Dim q2 As Double
   Dim s1, s2 As String
   Dim q3 As Double
   s1 = "1.1212"
   s2 = "1.1210"
   q1 = s1
   q2 = s2
   q3 = q1 - q2
   MsgBox q3
End Sub

На выходе q3=1.99999999999978E-04, а не 0,0002, почему так происходит и как от этого избавиться? Пока просто округляю до нужного знака.
Re: Приведение типа потом вычитание
От: Peter Fleischer Германия www.informtoools.de
Дата: 03.05.05 15:42
Оценка:
"Igore" <25308@users.rsdn.ru> schrieb im Newsbeitrag news:1154608@news.rsdn.ru...
> Что-то я не могу понять почему это неправильно работает.
>
>
> Private Sub Form_Load()
>   Dim q1 As Double
>   Dim q2 As Double
>   Dim s1, s2 As String
>   Dim q3 As Double
>   s1 = "1.1212"
>   s2 = "1.1210"
>   q1 = s1
>   q2 = s2
>   q3 = q1 - q2
>   MsgBox q3
> End Sub
>

> На выходе q3=1.99999999999978E-04, а не 0,0002, почему так происходит и как от этого избавиться? Пока просто округляю до нужного знака.

Из-за ограниченной разрядной сетки процессора могут быть такие "неточности" при преобразовании из двоичного в десятичное представление (и наоборот). Нади либо брать целочисленные числа, либо округлять.

Peter
Posted via RSDN NNTP Server 1.9
Re[2]: Приведение типа потом вычитание
От: Igore Россия  
Дата: 03.05.05 15:50
Оценка:
Здравствуйте, Peter Fleischer, Вы писали:

PF>Из-за ограниченной разрядной сетки процессора могут быть такие "неточности" при преобразовании из двоичного в десятичное представление (и наоборот). Нади либо брать целочисленные числа, либо округлять.


PF>Peter



Как выеснилось ошибка еще проще, мне просто интересно, это у меня одного такое или нет.
   Dim q3 As Double
   q3 = 1.1212 - 1.1211
   MsgBox q3 'q3<>0.0001
Re[3]: Приведение типа потом вычитание
От: Peter Fleischer Германия www.informtoools.de
Дата: 03.05.05 16:15
Оценка:
...
> Как выеснилось ошибка еще проще, мне просто интересно, это у меня одного такое или нет.
>   Dim q3 As Double
>   q3 = 1.1212 - 1.1211
>   MsgBox q3 'q3<>0.0001

Это у всех процессоров X86 так. Если хочешь точно, то примени соответствующие типы, напр. так:

[vb]
   Dim q3 As Double
   q3 = CDec(1.1212) - CDec(1.1211)
   MsgBox q3 'q3=0.0001


Peter
Posted via RSDN NNTP Server 1.9
Re[4]: Приведение типа потом вычитание
От: Igore Россия  
Дата: 03.05.05 16:27
Оценка:
Здравствуйте, Peter Fleischer, Вы писали:


PF>Это у всех процессоров X86 так. Если хочешь точно, то примени соответствующие типы, напр. так:


PF>
PF>   Dim q3 As Double
PF>   q3 = CDec(1.1212) - CDec(1.1211)
PF>   MsgBox q3 'q3=0.0001
PF>


Спасибо так красивее, но почему во всех других языках которые я знаю, результат правильный. При делении ошибки могут накапливаться это ясно, но откуда возникаю ошибки прм таком простом вычитании
Re[5]: Приведение типа потом вычитание
От: Peter Fleischer Германия www.informtoools.de
Дата: 03.05.05 18:35
Оценка:
...
> Спасибо так красивее, но почему во всех других языках которые я знаю, результат правильный. ...

Какие же языки знаешь для Intel X86?

Проимер на C#, который дает аналогичные результаты:

Double q3;
q3 = 1.1212 - 1.1211;
MessageBox.Show(q3.ToString());
q3 = (Double)(Decimal.Parse("1,1212") - Decimal.Parse("1,1211"));
MessageBox.Show(q3.ToString());


Peter
Posted via RSDN NNTP Server 1.9
Re[6]: Приведение типа потом вычитание
От: ACR Россия  
Дата: 03.05.05 19:00
Оценка:
хм... вот например консолька на С++

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
double d1,d2,d3;
d1 = 1.1212L;
d2 = 1.1211L;
d3 = d1 — d2;
printf("\n res=%e",d3);


return 0;
}

выдает:
res=1.000000e-004
Re[5]: Приведение типа потом вычитание
От: GarryIV  
Дата: 03.05.05 19:18
Оценка:
Hello, Igore!

PF>> Это у всех процессоров X86 так. Если хочешь точно, то примени


I> Спасибо так красивее, но почему во всех других языках которые я знаю,

I> результат правильный. При делении ошибки могут накапливаться это ясно,
I> но откуда возникаю ошибки прм таком простом вычитании

Дабл устроен так что физически не может хранить число 0.2 точно, так как получается бесконечная периодическая двоичная дробь.
То есть ошибка получается уже при присваивании doubleVar = 0.2 От используемого языка не зависит, что подтверждается массой подобных вопросов и в конфе С++ и NET и остальных наверно тоже .
Posted via RSDN NNTP Server 1.9
WBR, Igor Evgrafov
Re[6]: Приведение типа потом вычитание
От: ACR Россия  
Дата: 03.05.05 19:24
Оценка:
да точно
#include "stdafx.h"
#include <stdlib.h>

int _tmain(int argc, _TCHAR* argv[])
{
double d1,d2,d3;

d1 = atof("1.1212");
d2 = atof("1.1211");
d3 = d1 — d2;
printf("\n res=%.40e",d3);

return 0;
}

выдает res=9.9999999999988987000000000000000000000000e-005

от используемого языка зависит точность по умолчанию при преобразовании в строку
Re[7]: Приведение типа потом вычитание
От: Peter Fleischer Германия www.informtoools.de
Дата: 03.05.05 19:59
Оценка:
"ACR" <11679@users.rsdn.ru> schrieb im Newsbeitrag news:1154897@news.rsdn.ru...
> хм... вот например консолька на С++
>
> #include "stdafx.h"
>
> int _tmain(int argc, _TCHAR* argv[])
> {
> double d1,d2,d3;
> d1 = 1.1212L;
> d2 = 1.1211L;
> d3 = d1 — d2;
> printf("\n res=%e",d3);
>
>
> return 0;
> }
>
> выдает:
> res=1.000000e-004

%e без точночти (precision) выдает результат, округленный до 6 десятичных знаков.

Каков результат, если брать по-больше знаков?

Peter
Posted via RSDN NNTP Server 1.9
Re: Приведение типа потом вычитание
От: AntoxaM  
Дата: 03.05.05 20:45
Оценка:
Здравствуйте, Igore, Вы писали:

I>Что-то я не могу понять почему это неправильно работает.

...
I>На выходе q3=1.99999999999978E-04, а не 0,0002, почему так происходит и как от этого избавиться? Пока просто округляю до нужного знака.
Всё правильно — это же числа с плавающей точкой.
Если нужны числа с фиксированой запятой, то можно глянуть на decimal.
Так получишь 0,0002:
   Dim q1
   Dim q2
   Dim s1, s2 As String
   Dim q3
   s1 = "1.1212"
   s2 = "1.1210"
   q1 = CDec(s1)
   q2 = CDec(s2)
   q3 = q1 - q2
   MsgBox q3
silent... << RSDN@Home 1.1.4 beta 6a rev. 439>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.