Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.50/10: Рейтинг темы: голосов - 10, средняя оценка - 4.50
DeKaN
34 / 34 / 8
Регистрация: 10.02.2010
Сообщений: 184
1

Учим математику

27.06.2011, 16:53. Просмотров 1909. Ответов 14
Метки нет (Все метки)

Всем привет...Возникла проблема, которую я не могу объяснить, и прошу помощи у вас...
дело вот в чем: когда я учился в школе мне говорили, что если

x=a+c и b=x-c, то a-b==0

Но я столкнулся с тем, что это не так((
смотрите, делаю вот что:
C#
1
2
3
4
5
6
7
public static double GetB(PointF p)
{
   double a = (double)((double)p.Y + (double)Max) / (double)Step;
   double x = a + (double)c;
   double b = x - (double)c;
   return b;
}
>> Не смотрите что у меня много раз используется приведение типов в (double)...это я эксперементировал, т.к. думал что это из за того, что переменные Max, Step и c имеют тип float )) <<

Так вот...если я сложу a+b, то получу не 0, а "-0.0000019073486328125".
Мой компьютер разучился считать, или как???
0
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.06.2011, 16:53
Ответы с готовыми решениями:

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

Структуры. Распечатать список тех учителей школы, которые преподают математику и информатику
Распечатать список тех учителей школы, которые преподают математику и информатику, указать стаж их...

Учим систему разговаривать!
Здравствуйте, начну с того что я чайник каких еще поискать надо. Отойдя от вступления подойдем...

Эксплуатация, советуем, предостерегаем, учим.
Начну. Toyota, требует замену масла каждые 10 000 пробега (для России), автоВаз 15 тыс. Кто...

Учим code::blocks компилировать gcc компилятором
не умею пользоваться форумом, переместите в нужную ветку если не туда попал в общем те кто...

14
freeba
Неадекват
1289 / 1086 / 206
Регистрация: 02.04.2010
Сообщений: 2,501
Записей в блоге: 2
Завершенные тесты: 2
27.06.2011, 20:58 2
Цитата Сообщение от DeKaN Посмотреть сообщение
Мой компьютер разучился считать, или как???
Дело в IEEE 754 (IEEE Standard Binary Floating-Point Arithmetic). Если нужна заданная точность, то используй числа с фиксированной запятой.
2
Xero201
64 / 62 / 19
Регистрация: 27.12.2008
Сообщений: 212
27.06.2011, 22:52 3
Возможно дело в том, что
a-b==0
не тоже самое что и
сложу a+b, то получу не 0
и тем более не
return b;
0
DeKaN
34 / 34 / 8
Регистрация: 10.02.2010
Сообщений: 184
28.06.2011, 05:29  [ТС] 4
причем тут return b....я спрашивал про другое, почему double x = a + (double)c; считается не правильно...т.к. если я после этого от x отниму (double)c, то не получу a

Добавлено через 8 минут
оказалось, чтороблема вот в чем:
p.Y + Max == Max...
т.е. просто не прибавляет...
p.Y = 0.00000458 - не очень уж малое число...почему же не прибавляет?

Добавлено через 9 минут
при Debug, в контрольных значениях пишу:
350+0.00000458...получаю 350.00000457861
то что надо...
однако
double a = (double)p.Y + (double)Max, где Max=350, p.Y=0.00000458
в результате a=350
0
28.06.2011, 05:29
Xero201
64 / 62 / 19
Регистрация: 27.12.2008
Сообщений: 212
28.06.2011, 12:43 5
Цитата Сообщение от DeKaN Посмотреть сообщение
причем тут return b....я спрашивал про другое
у тебя просто первый пост кривой, в математическом примере речь о a-b = 0, в листинге о b, а в резюме о a+b, на что я и указал.
Думаю, если приведешь все в порядок, будет считать правильно. Вот:
C#
1
2
3
4
5
6
7
8
9
10
float p = 0.00000458F;
float MAX = 450;
 
double a = (double)MAX + (double)p;//450.00000458000022
double aa = (double)(MAX+p);//450.00000458000022
double aar = (double)MAX + p;//450.00000458000022
double aal = MAX + (double)p;//450.00000458000022
 
double aaa = MAX + p;//450
float af = MAX + p;//450
1
s-kvv
76 / 73 / 9
Регистрация: 09.06.2010
Сообщений: 206
28.06.2011, 13:19 6
Я то же с подобным сталкивался
Тут дело в особенности работы операций чисел с плавающей точкой
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    class Program
    {
        static void Main(string[] args)
        {
            double d=0.0;
            for (d = -1.0; d < 1; d += 0.2)
                ;
            Console.WriteLine(d);
 
            for (d = -1.0; d < 1; d += 0.1)
                ;
            Console.WriteLine(d);
 
            Console.ReadKey();
        }
    }
На моей машине это выглядит так
Название: Безымянный.GIF
Просмотров: 139

Размер: 1.6 Кб
У кого-то другого, думаю, может быть по-другому
1
Xero201
64 / 62 / 19
Регистрация: 27.12.2008
Сообщений: 212
28.06.2011, 13:45 7
Цитата Сообщение от s-kvv Посмотреть сообщение
Я то же с подобным сталкивался
Тут дело в особенности работы операций чисел с плавающей точкой
Ну у тебя немножко другое: накопилась погрешность в 0.0000..0001, из-за чего в тот момент, когда d должно было равняться 1, оно было 0.9999..999, поэтому еще понадобилось добавление 0.1.
У DeKaN просто отрубает дробную часть, что связано скорее всего в неправильном присвоении этого значения, либо преобразовании.
0
s-kvv
76 / 73 / 9
Регистрация: 09.06.2010
Сообщений: 206
28.06.2011, 15:07 8
Не пойму....
Какая погрешность, если нет никакого деления, умножения?
Есть только сложение констант, и нет каких-то значительных передвижений в разрядах числа
Откуда взялась эта погрешность???
По-моему примеры аналогичны
0
devstart
15 / 15 / 1
Регистрация: 08.06.2011
Сообщений: 34
28.06.2011, 15:47 9
Цитата Сообщение от s-kvv Посмотреть сообщение
Не пойму....
Какая погрешность, если нет никакого деления, умножения?
Есть только сложение констант, и нет каких-то значительных передвижений в разрядах числа
Откуда взялась эта погрешность???
По-моему примеры аналогичны
В первом же ответе темы дали исчерпывающий ответ, но Вы продолжаете задавать вопросы.
Видимо, Вам элементарно лень разобраться - что же там в стандарте пишут про определения типов.
Ну если так - могли бы разобраться в типах .Net и в виде представления чисел в машинном коде, однако, видимо и этим Вы заняться не хотите. За Вас "точить топор" никто не будет.
Еще раз: число с плавающей точкой не используется для обработки точных значений. Оно "приблизительное " по определению. Подробности в гугл.

Если хотите начать разбираться в математике и способах компьютерного представления чисел - загляните в вики, раздел Числа_с_плавающей_запятой
http://ru.wikipedia.org/wiki/%D0%A7%...82%D0%BE%D0%B9
1
s-kvv
76 / 73 / 9
Регистрация: 09.06.2010
Сообщений: 206
28.06.2011, 16:56 10
Цитата Сообщение от devstart Посмотреть сообщение
В первом же ответе темы дали исчерпывающий ответ, но Вы продолжаете задавать вопросы.
Видимо, Вам элементарно лень разобраться - что же там в стандарте пишут про определения типов.
Ну если так - могли бы разобраться в типах .Net и в виде представления чисел в машинном коде, однако, видимо и этим Вы заняться не хотите. За Вас "точить топор" никто не будет.
Еще раз: число с плавающей точкой не используется для обработки точных значений. Оно "приблизительное " по определению. Подробности в гугл.

Если хотите начать разбираться в математике и способах компьютерного представления чисел - загляните в вики, раздел Числа_с_плавающей_запятой
http://ru.wikipedia.org/wiki/%D0%A7%...82%D0%BE%D0%B9
Тапор себе сам поточи
Привел пример и утверждаю что и в первом и во втором случае суть проблеммы одна, не спорю с первым ответом, а наоборот его подтверждаю. Умножение и др. по этому так и работают
И раз ты такой умный, не отсылай к вики, ответь сам - как при сложении единицы с константой 0.1 появляются доп разряды в десятитысячных долях?
Можешь еще круче ошарашить и с точки зрения представления в двоичном коде double привести анализ, похлопаю тогда
А пока этого не сделал, держи эмоции при себе, не думай что интернет есть только у тебя, и пытайся вчитаться то о чем пишут. Все разные и мысли выражают по-разному
0
devstart
15 / 15 / 1
Регистрация: 08.06.2011
Сообщений: 34
28.06.2011, 18:45 11
Цитата Сообщение от s-kvv Посмотреть сообщение
Тапор себе сам поточи
Привел пример и утверждаю что и в первом и во втором случае суть проблеммы одна, не спорю с первым ответом, а наоборот его подтверждаю. Умножение и др. по этому так и работают
И раз ты такой умный, не отсылай к вики, ответь сам - как при сложении единицы с константой 0.1 появляются доп разряды в десятитысячных долях?
Можешь еще круче ошарашить и с точки зрения представления в двоичном коде double привести анализ, похлопаю тогда
А пока этого не сделал, держи эмоции при себе, не думай что интернет есть только у тебя, и пытайся вчитаться то о чем пишут. Все разные и мысли выражают по-разному
Видимо совсем плохи дела.
Ваш вопрос:
"И раз ты такой умный, не отсылай к вики, ответь сам - как при сложении единицы с константой 0.1 появляются доп разряды в десятитысячных долях?"
Ответ в моем предыдущем сообщении:
"Еще раз: число с плавающей точкой не используется для обработки точных значений. Оно "приблизительное " по определению". Почему так происходит - описано в вики в разделе "Машинная эпсилон"

Вы тут пытаетесь, выражаясь метафорично "подъемным краном отмерить дозу лекарства больному".
Воспользуйтесь весами (decimal).

"Можешь еще круче ошарашить и с точки зрения представления в двоичном коде double привести анализ, похлопаю тогда"
Вежливости как-то не хватает, или толсто троллите. Нет желания бисер метать. Почитайте про то как формат с плавающей точкой реализован в компьютере. Если понимаете что такое экспоненциальная запись числа, то у Вас не должно быть с этим проблем.

Какбе набор опыта в программировании подразумевает что человек способен по наводящим ответам сам воссоздать картину происходящего. Вам подсказали:
1. стандарт по типам.
2. точнее подсказали что double и single суть неточные типы по определению и в этом нет магии, они так и задуманы.
Нормальный человек поблагодарил бы, от Вас даже не ожидаю.
1
s-kvv
76 / 73 / 9
Регистрация: 09.06.2010
Сообщений: 206
29.06.2011, 02:02 12
Цитата Сообщение от devstart Посмотреть сообщение
Ваш вопрос:
"И раз ты такой умный, не отсылай к вики, ответь сам - как при сложении единицы с константой 0.1 появляются доп разряды в десятитысячных долях?"
Ответ в моем предыдущем сообщении:
"Еще раз: число с плавающей точкой не используется для обработки точных значений. Оно "приблизительное " по определению". Почему так происходит - описано в вики в разделе "Машинная эпсилон"
Ты думаешь что только ты об этом читал и знаешь
Цитата Сообщение от devstart Посмотреть сообщение
Какбе набор опыта в программировании подразумевает что человек способен по наводящим ответам сам воссоздать картину происходящего.
Вам подсказали:
1. стандарт по типам.
2. точнее подсказали что double и single суть неточные типы по определению и в этом нет магии, они так и задуманы.
Нормальный человек поблагодарил бы, от Вас даже не ожидаю.
1. Суть моего первого сообщения и примера не заключалась в вопросе к кому-то.
2. Я привел пример, с которым столкнулся. Для меня показалось в нем интересным то, что мантиса очень мала, експонента числа оличается только на 1, но всеравно это приводит к неверному вычислению. И еще - что это все неочевидно
3. О том, что эти числа приблезительные по определению и так понятно
4. Этот стандарт я читал и до этого.
5. То что в этом нет магии соответственно понимаю
6. За что тебе спасибо? За "топор"?
ЗЫ. Читать что пишут научись, а потом разглагольствуй
0
DeKaN
34 / 34 / 8
Регистрация: 10.02.2010
Сообщений: 184
29.06.2011, 04:20  [ТС] 13
так...нашёл в чем была причина, но от этого не легче((
Я использую в приложении Manager DirectX, так вот, смотрите что происходит:
C#
1
2
3
4
5
float p = 0.00000458F;
float MAX = 450;
double a1 = (double)MAX + (double)p; //450.00000458000022
myDevice = new Device(0, DeviceType.Hardware, handle, CreateFlags.HardwareVertexProcessing | CreateFlags.PureDevice, setting);
double a2 = (double)MAX + (double)p; //450.0
т.е. после создания устройства, точность вычислний падает...кто-нибудь знает как это исправить?
0
devstart
15 / 15 / 1
Регистрация: 08.06.2011
Сообщений: 34
29.06.2011, 12:05 14
Лучший ответ Сообщение было отмечено как решение

Решение

Цитата Сообщение от s-kvv Посмотреть сообщение
Ты думаешь что только ты об этом читал и знаешь

1. Суть моего первого сообщения и примера не заключалась в вопросе к кому-то.
2. Я привел пример, с которым столкнулся. Для меня показалось в нем интересным то, что мантиса очень мала, експонента числа оличается только на 1, но всеравно это приводит к неверному вычислению. И еще - что это все неочевидно
3. О том, что эти числа приблезительные по определению и так понятно
4. Этот стандарт я читал и до этого.
5. То что в этом нет магии соответственно понимаю
6. За что тебе спасибо? За "топор"?
ЗЫ. Читать что пишут научись, а потом разглагольствуй
Ок. Я поясню свою позицию.
В тему подключился человек, который
а) проблему видел, б) проблему запомнил, в) она его заинтересовала, т.к. не лень было написать пост и даже свой пример найти.
И при этом, несмотря на то, что есть весь инструментарий .Net, за довольно долгое время человек так и не докопался почему так происходит.
Я вчера набросал примерчик по твоему коду, суть сводится к получению данных, реально хранящихся в double, приблизительно вот так:
C#
1
long bits = BitConverter.DoubleToInt64Bits(d);
Там требуются еще телодвижения, чтобы отковырять из битов мантиссу, экспоненту и знак, но там несложно, и примеры есть.

Суть в чем - удобное для нас представление числа, и то, как оно в памяти хранится - они сильно разные. Это, например, можно и так себе представлять, исходя из способов машинного представления чисел. Именно пошагово посмотреть какие биты куда прибавляются - не хочется докапываться. Приведу фрагмент выходных данных по твоему примеру.
Код :
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
            
double d;
            double dDif = 0.2;
            DoublePresentation dPresent;
 
            dPresent = new DoublePresentation(dDif);
            Console.WriteLine(dPresent.ToString());
 
            Console.WriteLine("Первый проход");
            for (d = -1.0; d < 1; d += 0.2)
            {
                dPresent = new DoublePresentation(d);
                Console.WriteLine(dPresent.ToString());
            }
            Console.WriteLine("Первый проход окончен");
            ...
 
            Console.ReadKey();
Фрагмент вывода (суть понятна и так):
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
значение double = 0,2, в экспоненциальной форме = 2,000000E-001
биты: = 3FC999999999999A, отрицательное = False,
РеальноХранимаяМашиннаяЭкспонента = -54, РеальноХранимаяМашиннаяМантисса = 36028
79701896397
Реально хранимое в double число: 0,2000000000001519552715836261
 
Первый проход
значение double = -1, в экспоненциальной форме = -1,000000E+000
биты: = BFF0000000000000, отрицательное = True,
РеальноХранимаяМашиннаяЭкспонента = 0, РеальноХранимаяМашиннаяМантисса = 1
Реально хранимое в double число: 1
 
значение double = -0,8, в экспоненциальной форме = -8,000000E-001
биты: = BFE999999999999A, отрицательное = True,
РеальноХранимаяМашиннаяЭкспонента = -52, РеальноХранимаяМашиннаяМантисса = 36028
79701896397
Реально хранимое в double число: 0,799999999999887245145955225
 
значение double = -0,6, в экспоненциальной форме = -6,000000E-001
биты: = BFE3333333333334, отрицательное = True,
РеальноХранимаяМашиннаяЭкспонента = -51, РеальноХранимаяМашиннаяМантисса = 13510
79888211149
Реально хранимое в double число: 0,6000000000000505973594387649
 
значение double = -0,4, в экспоненциальной форме = -4,000000E-001
биты: = BFD999999999999B, отрицательное = True,
РеальноХранимаяМашиннаяЭкспонента = -54, РеальноХранимаяМашиннаяМантисса = 72057
59403792795
Реально хранимое в double число: 0,4000000000003039660543184835
 
значение double = -0,2, в экспоненциальной форме = -2,000000E-001
биты: = BFC999999999999C, отрицательное = True,
РеальноХранимаяМашиннаяЭкспонента = -53, РеальноХранимаяМашиннаяМантисса = 18014
39850948199
Реально хранимое в double число: 0,1999999999999718667976400375
Добавлено через 3 минуты
Цитата Сообщение от DeKaN Посмотреть сообщение
так...нашёл в чем была причина, но от этого не легче((
Я использую в приложении Manager DirectX, так вот, смотрите что происходит:
C#
1
2
3
4
5
float p = 0.00000458F;
float MAX = 450;
double a1 = (double)MAX + (double)p; //450.00000458000022
myDevice = new Device(0, DeviceType.Hardware, handle, CreateFlags.HardwareVertexProcessing | CreateFlags.PureDevice, setting);
double a2 = (double)MAX + (double)p; //450.0
т.е. после создания устройства, точность вычислний падает...кто-нибудь знает как это исправить?
Для Вас все проще, нужно только понять чего же вы хотите.
1. Если интересует точность вычислений, и можно немного пожертвовать производительностью - юзайте тип decimal. Он позволяет хранить дробные числа с огромной точностью и не допускает погрешностей. (рекомандованный тип для работы с финансовыми вычислениями)
2. Если хотите сохранить быстроту работы double и single - определите точность, которая вам нужна и где нужны точные значения - пользуйтесь округлением (тут нужно экспериментировать, т.к. может и не получиться, если Вам нужна очень большая точность)
4
DeKaN
34 / 34 / 8
Регистрация: 10.02.2010
Сообщений: 184
29.06.2011, 14:47  [ТС] 15
определите точность, которая вам нужна и где нужны точные значения
Не, это не поможет, я же написал, что округляет до 0.00001...это явно не в точности дело..., слишком малая она для float и тем более для double...
всё гораздо проще, надо просто добавить CreateFlags.FpuPreserve, и всё стало на круги своя))
C#
1
myDevice = new Device(0, DeviceType.Hardware, handle, CreateFlags.HardwareVertexProcessing | CreateFlags.PureDevice|CreateFlags.FpuPreserve, setting);
2
29.06.2011, 14:47
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.06.2011, 14:47

Учим компьютер играть в Гомоку (пять в ряд)
Отработал защиту бота, (я играю крестиками компьютер нулями) начал решать задачу с конца. Бот еще...

Учим компьютер играть в Гомоку (пять в ряд)
Отработал защиту бота, (я играю крестиками компьютер нулями) начал решать задачу с конца. Бот...

Учим zend framework 2 в два раза быстрее
Доброго времени суток. Коротко о сути. Хочу освоить zend framework 2 но в связи с нестачей...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

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