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

Засада с машинным эпсилон, или Либо я дурак - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 18, средняя оценка - 4.89
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
07.08.2012, 18:08     Засада с машинным эпсилон, или Либо я дурак #1
Эту задачку выполняют все начинающие.

Так вот, берём два простеньких кода. Они настолько коротки, тупы и очевидны, что я даже не комментировал их.

Первый, работает нормально.
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
#include <iostream>
 
using std::cout;
using std::endl;
 
#include <iomanip>
 
using std::ios;
using std::setiosflags;
 
int main()
{
    float a, b, e;
    int counter;
 
    e=1.0; b=1.0; a=1.0;
 
    counter=0;
 
    do
    {
        e=e/2;
        a=b+e/2;
 
        counter++;
    }while (a>b);
 
    cout << setiosflags(ios::scientific);
 
    cout << sizeof(e) << endl;
    cout << "eps=" << e << endl;
    cout << "counter=" << counter << endl;
 
    return 0;
}
Второй, тоже вроде с виду пристойный, ещё и короче первого - казалось бы, ляпота!

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
#include <iostream>
 
using std::cout;
using std::endl;
 
#include <iomanip>
 
using std::ios;
using std::setiosflags;
 
int main()
{
    float a, e;
    int counter;
 
    e=1.0; a=1.0;
 
    counter=0;
    while (e/2+a>a)
    {
        e=e/2;
        counter++;
    }
 
    cout << setiosflags(ios::scientific);
 
    cout << sizeof(e) << endl;
    cout << "eps=" << e << endl;
    cout << "counter=" << counter << endl;
 
    return 0;
}
Оба кода написаны с помощью Qt Creator 2.0.1.

Определить машинное эпсилон с помощью первого кода для разных типов можно, меняя одно-единственное слово в тексте, ака тип переменных (ну заломало меня извращаться, пусть будет пока так). Для float код даёт значение эпсилон 1.19e-7, для double 2.22e-16, для long double 1.08e-19. *Голосом Малышевой* Это - нормально.
НО: второй код для ЛЮБОГО типа выдаёт 1.08e-19. То бишь он какого-то хрена полосатого делает преобразование типа. Вопрос: ГДЕ тут это может быть?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.08.2012, 20:05     Засада с машинным эпсилон, или Либо я дурак #2
Ну не знаю, вот тут всё работает как надо.
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
07.08.2012, 20:31  [ТС]     Засада с машинным эпсилон, или Либо я дурак #3
Походу компилятор дурак. Да, Qt подставил подножку, маладец.
Ща пойду обновлюсь. За ссылочку на ресурс, кстати, спасибо, полезная она.

Тока где именно здесь загвоздка - непонятно всё равно. Блин, как только не колдую - не получается.
Avazart
 Аватар для Avazart
6901 / 5141 / 252
Регистрация: 10.12.2010
Сообщений: 22,604
Записей в блоге: 17
07.08.2012, 21:50     Засада с машинным эпсилон, или Либо я дурак #4
Проблема не в IDE ...

Проверил на Builder-е
Код
Текущая кодовая страница: 1251
4
eps=1.084202e-19
counter=63
Для продолжения нажмите любую клавишу . . .
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
08.08.2012, 10:09  [ТС]     Засада с машинным эпсилон, или Либо я дурак #5
Цитата Сообщение от Avazart Посмотреть сообщение
Проблема не в IDE ...
А в чём же тогда?

Самое странное, что код совершенно законный. Удивительное рядом.
-=ЮрА=-
Заблокирован
Автор FAQ
08.08.2012, 11:49     Засада с машинным эпсилон, или Либо я дурак #6
kozlik_kozlik, никакой компилятор не дурак - у тебя тип счётчика какой?Нука смотрим
Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
int counter;
- т.е максимум сможем реализовать около 2.5E6 операций деления, по твоему 1,000006 скажем это число которое отличается от 1-цы в 15-м знаке???
-=ЮрА=-
Заблокирован
Автор FAQ
08.08.2012, 11:54     Засада с машинным эпсилон, или Либо я дурак #7
kozlik_kozlik, вот твой же код только с верными(в плане превышения их макс значений) типами переменных
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
#include <iomanip>
#include <iostream>
using namespace std; 
 
int main()
{
    double a = 1;
    double e = 1;
    double counter = 0;
 
    while (a < a + e/2)
    {
        e = e/2;
        counter++;
    }
 
    cout << setiosflags(ios::scientific);
 
    cout << sizeof(e) << endl;
    cout << "eps=" << e << endl;
    cout << "counter=" << counter << endl;
 
    return 0;
}
http://liveworkspace.org/code/5125ab...59ed05f22aaaeb
Миниатюры
Засада с машинным эпсилон, или Либо я дурак  
-=ЮрА=-
Заблокирован
Автор FAQ
08.08.2012, 11:57     Засада с машинным эпсилон, или Либо я дурак #8
PS: этот цикл
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
while (a < a + e/2)
* * {
* * * * e = e/2;
* * * * counter++;
* * }
можно записать вот так, для сокращения записи
C++
1
2
while (a < a + (e /= 2))
        counter++;
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,048
08.08.2012, 12:03     Засада с машинным эпсилон, или Либо я дурак #9
Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
C++
1
2
3
4
5
6
do
 {
 e=e/2;
 a=b+e/2;
counter++;
 }while (a>b);

Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
C++
1
2
3
4
5
while (e/2+a>a)
 {
 e=e/2;
 counter++;
 }
коды то не равнозначны
в первом идет сравнение с е/4
во втором е/2
первый надо переписать так
C++
1
2
3
4
5
6
do
 {
 e=e/2;
 a=b+e;
counter++;
 }while (a>b);
или так
C++
1
2
3
4
5
6
do
 {
 a=b+e/2;
 e=e/2;
counter++;
 }while (a>b);
Добавлено через 3 минуты
Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
что я даже не комментировал их.
а прокомментировал бы нашел бы ошибку
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
09.08.2012, 21:46  [ТС]     Засада с машинным эпсилон, или Либо я дурак #10
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
kozlik_kozlik, никакой компилятор не дурак - у тебя тип счётчика какой?Нука смотрим
- т.е максимум сможем реализовать около 2.5E6 операций деления, по твоему 1,000006 скажем это число которое отличается от 1-цы в 15-м знаке???
А ты вставь в цикл

cout << counter << endl;

и убедись, что до переполнения тут как до Китая раком. Что такое геометрическая прогрессия, в курсе? Так вот она имеет такое замечательное свойство - очень быстро расти/падать.
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,048
09.08.2012, 21:55     Засада с машинным эпсилон, или Либо я дурак #11
kozlik_kozlik,
А ты мое сообщение читал????
у тебя два разных кода
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
09.08.2012, 22:20  [ТС]     Засада с машинным эпсилон, или Либо я дурак #12
ValeryS, раз коды не равнозначны, то почему дают одинаковый результат (для long double исесьна)? Особенно это хорошо видно, если выводить в процессе номер и эпсилон. Не иначе как б-жье чудо. Равнозначны они. Попробуй просто в голове прокрутить, что там происходит, первые несколько шагов, буквально с калькулятором и текстовым редактором (бумажку не буду рекомендовать, уж так и быть).

Или просто взгляни на консоль, если лень.
Первый код
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
#include <iostream>
 
using std::cout;
using std::endl;
 
#include <iomanip>
 
using std::ios;
using std::setiosflags;
 
int main()
{
    long double a, b, e;
    int counter;
 
    e=1.0; b=1.0; a=1.0;
 
    counter=0;
 
    do
    {
        e=e/2;
        a=b+e/2;
 
        cout << counter << " " << e << endl;
 
        counter++;
    }while (a>b);
 
    cout << endl;
 
    cout << setiosflags(ios::scientific);
 
    cout << sizeof(e) << endl;
    cout << "eps=" << e << endl;
    cout << "counter=" << counter << endl;
 
    return 0;
}
Второй код
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
#include <iostream>
 
using std::cout;
using std::endl;
 
#include <iomanip>
 
using std::ios;
using std::setiosflags;
 
int main()
{
    long double a, e;
    int counter;
 
    e=1.0; a=1.0;
 
    counter=0;
    while (e/2+a>a)
    {
        e=e/2;
 
        cout << counter << " " << e << endl;
 
        counter++;
    }
 
    cout << endl;
 
    cout << setiosflags(ios::scientific);
 
    cout << sizeof(e) << endl;
    cout << "eps=" << e << endl;
    cout << "counter=" << counter << endl;
 
    return 0;
}
Добавлено через 4 минуты
ValeryS, на вот тебе результаты работы первого кода и второго:
http://ideone.com/leMLY
http://ideone.com/3zcTb

Нет тут ошибки.
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,048
09.08.2012, 22:52     Засада с машинным эпсилон, или Либо я дурак #13
Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
Попробуй просто в голове прокрутить, что там происходит,
кручу
первый код первая проходка(дальше лень)
C++
1
2
3
4
5
6
7
8
  e=1.0; b=1.0; a=1.0;
 do
    {
        e=e/2;// е =0.5
        a=b+e/2;a=1.0+0.25  1.0 +0.5/2
 
        counter++; //1
    }while (a>b);  1.25>1
второй код первая проходка
C++
1
2
3
4
5
6
7
8
 e=1.0; a=1.0;
 
    counter=0;
    while (e/2+a>a)// 0.5+1>1.0 1.5>1.0
    {
        e=e/2; //e= 0.5
        counter++;//1
    }
Если вы считаете что 1.5>1.0 это тоже самое что 1.25>1
тогда извините

Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
то почему дают одинаковый результат (для long double исесьна)?
а для других???
Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
Особенно это хорошо видно, если выводить в процессе номер и эпсилон. Не иначе как б-жье чудо.
класная отмазка

Добавлено через 4 минуты
еще раз
Цитата Сообщение от ValeryS Посмотреть сообщение
C++
1
2
3
4
5
6
 do
 {
 e=e/2;
 a=b+e;
counter++;
 }while (a>b)
;
или так
C++
1
2
3
4
5
6
do
 {
 a=b+e/2;
 e=e/2;
counter++;
 }while (a>b)
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
09.08.2012, 23:12  [ТС]     Засада с машинным эпсилон, или Либо я дурак #14
ValeryS

Если вы считаете что 1.5>1.0 это тоже самое что 1.25>1
тогда извините
А вот я сейчас спрошу, почему должно быть "то же самое", и ты не сможешь ответить.

Давай по порядку. Вот просто по-тупому.

Представим, что есть такой очень хреновый тип данных, для которого 1,125 уже неотличимо от 1, а всё, что больше, отличимо. Ну так, чтобы шагов поменьше было.

Первый код.
Первый оборот цикла: е=0,5, а=1,25, счётчик=1, а отличается от 1, продолжаем.
Второй оборот цикла: е=0,25, а=1,125, счётчик=2, а не отличается от 1, остановились.

Результат: е=0,25, 2 шага.

Второй код.
Первый оборот цикла: сравниваем 1,5 и 1, различается, считаем дальше, е=0,5, счётчик=1.
Второй оборот цикла: сравниваем 1,25 и 1, различаются, считаем дальше, е=0,25, счётчик=2.
Третий оборот цикла: сравниваем 1,125 и 1, не различаются, выходим из цикла.

Результат: е=0,25, 2 шага.

А теперь ткни пальцем, что тут неправильно. Единственная неточность - второй код делает три шага, а у меня выводится два. Похрен, мне надо было оценить порядок величины, проблема вообще не в этом.

класная отмазка
Ага, не верь глазам своим (с) Козьма Прутков.

а для других???
Ты тему-то читал? В Qt Creator и Builder второй код даёт то же самое при любых типах из перечисленных, что и при long double. И именно в этом, если ты не заметил, и состоит проблема. Онлайн-IDE выдаёт абсолютно аналогичные результаты и при float, и при double, и при long double для обоих кодов. Собственно в этом и проблема - в Qt Creator и Builder происходит хреновина. ПРОБЛЕМА НЕ В ЛОГИКЕ ВЫЧИСЛЕНИЯ ЭПСИЛОН. ПРОБЛЕМА В СТРАННОМ ПРЕОБРАЗОВАНИИ ТИПА, КОТОРОГО НЕ ДОЛЖНО БЫТЬ, НО ПРОИСХОДИТ.

Люди, вы чего? Уже второй чудесатый "ответ" в теме. Да с каким гонором-то. Жара что ли так действует?
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,048
09.08.2012, 23:34     Засада с машинным эпсилон, или Либо я дурак #15
Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
Первый код.
Первый оборот цикла: е=0,5, а=1,25, счётчик=1, а отличается от 1, продолжаем.
Второй оборот цикла: е=0,25, а=1,125, счётчик=2, а не отличается от 1, остановились.
Результат: е=0,25, 2 шага.
Второй код.
Первый оборот цикла: сравниваем 1,5 и 1, различается, считаем дальше, е=0,5, счётчик=1.
Второй оборот цикла: сравниваем 1,25 и 1, различаются, считаем дальше, е=0,25, счётчик=2.
Третий оборот цикла: сравниваем 1,125 и 1, не различаются, выходим из цикла.
Результат: е=0,25, 2 шага.
миль пардон Мин Херц, обосрался
согласен полностью, признаю ошибку

Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
Да с каким гонором-то.
где ты гонор то увидел?
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
09.08.2012, 23:46  [ТС]     Засада с машинным эпсилон, или Либо я дурак #16
ValeryS, мир.

Так чё с типами-то? Диавольщина какая-то
alkagolik
 Аватар для alkagolik
1510 / 616 / 79
Регистрация: 15.07.2011
Сообщений: 3,552
10.08.2012, 04:15     Засада с машинным эпсилон, или Либо я дурак #17
g++ 4.6.3 три версии первого кода (float, double, long double) и три такие же версии второго. Может просто перекомпилировать файлик забыл и запускаешь один и тот же бинарь?
Bash
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
homehost# g++ test.cc
homehost# ./a.out 
4
eps=1.192093e-07
counter=23
homehost# g++ test.cc
homehost# ./a.out 
8
eps=2.220446e-16
counter=52
homehost# g++ test.cc
homehost# ./a.out 
16
eps=1.084202e-19
counter=63
homehost# g++ test.cc
homehost# ./a.out 
4
eps=1.192093e-07
counter=23
homehost# g++ test.cc
homehost# ./a.out 
8
eps=2.220446e-16
counter=52
homehost# g++ test.cc
homehost# ./a.out 
16
eps=1.084202e-19
counter=63
homehost#
kozlik_kozlik
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
10.08.2012, 18:16  [ТС]     Засада с машинным эпсилон, или Либо я дурак #18
alkagolik, стопудов нет.

Добавлено через 46 минут
С float помогло while ((float)(e/2.0+a)>a).

Ви таки будете смеяться, но с double такое почему-то не прокатывает%) Результат по-прежнему как для long double.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.08.2012, 20:34     Засада с машинным эпсилон, или Либо я дурак
Еще ссылки по теме:

C++ Засада на 3-ей Задаче
C++ Или я дурак, или компилятор смеется, вот только чувствую я дурак)
C++ Программа завершилась машинным кодом (0x0)

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

Или воспользуйтесь поиском по форуму:
alkagolik
 Аватар для alkagolik
1510 / 616 / 79
Регистрация: 15.07.2011
Сообщений: 3,552
10.08.2012, 20:34     Засада с машинным эпсилон, или Либо я дурак #19

Не по теме:

kozlik_kozlik, ну тогда в bug reports



Добавлено через 11 минут
kozlik_kozlik, есть имхо. в первом примере сравниваются две переменные встроенных типов, а во втором примере результат арифметической операции (скорее всего уложенный в long double) с переменной, которая автоматически приводится к большему типу.
Yandex
Объявления
10.08.2012, 20:34     Засада с машинным эпсилон, или Либо я дурак
Ответ Создать тему
Опции темы

Текущее время: 09:02. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru