Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.98/43: Рейтинг темы: голосов - 43, средняя оценка - 4.98
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
1

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

07.08.2012, 18:08. Показов 8444. Ответов 18
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Эту задачку выполняют все начинающие.

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

Первый, работает нормально.
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. То бишь он какого-то хрена полосатого делает преобразование типа. Вопрос: ГДЕ тут это может быть?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.08.2012, 18:08
Ответы с готовыми решениями:

Или я дурак, или компилятор смеется, вот только чувствую я дурак)
Ввожу 1939 совершенно верно, вожу какое либо число тоже совершенно верно. Не отрабатывает else { }...

Либо я дурак либо....
Короче задание такое...создать матрицу, определить сумму элементов в тех стлбцах которые не...

Или я дурак или лыжи не едут, склоняюсь к первому.
говорит необъявленный идентификатор относительно всех функций класса notebook. Пробовал все...

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

18
~ Эврика! ~
1256 / 1005 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
07.08.2012, 20:05 2
Ну не знаю, вот тут всё работает как надо.
1
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
07.08.2012, 20:31  [ТС] 3
Походу компилятор дурак. Да, Qt подставил подножку, маладец.
Ща пойду обновлюсь. За ссылочку на ресурс, кстати, спасибо, полезная она.

Тока где именно здесь загвоздка - непонятно всё равно. Блин, как только не колдую - не получается.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
07.08.2012, 21:50 4
Проблема не в IDE ...

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

Самое странное, что код совершенно законный. Удивительное рядом.
0
Заблокирован
Автор FAQ
08.08.2012, 11:49 6
kozlik_kozlik, никакой компилятор не дурак - у тебя тип счётчика какой?Нука смотрим
Цитата Сообщение от kozlik_kozlik Посмотреть сообщение
int counter;
- т.е максимум сможем реализовать около 2.5E6 операций деления, по твоему 1,000006 скажем это число которое отличается от 1-цы в 15-м знаке???
0
Заблокирован
Автор 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/... 05f22aaaeb
Миниатюры
Засада с машинным эпсилон, или Либо я дурак  
0
Заблокирован
Автор 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++;
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,523
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 Посмотреть сообщение
что я даже не комментировал их.
а прокомментировал бы нашел бы ошибку
0
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
09.08.2012, 21:46  [ТС] 10
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
kozlik_kozlik, никакой компилятор не дурак - у тебя тип счётчика какой?Нука смотрим
- т.е максимум сможем реализовать около 2.5E6 операций деления, по твоему 1,000006 скажем это число которое отличается от 1-цы в 15-м знаке???
А ты вставь в цикл

cout << counter << endl;

и убедись, что до переполнения тут как до Китая раком. Что такое геометрическая прогрессия, в курсе? Так вот она имеет такое замечательное свойство - очень быстро расти/падать.
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,523
09.08.2012, 21:55 11
kozlik_kozlik,
А ты мое сообщение читал????
у тебя два разных кода
0
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

Нет тут ошибки.
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,523
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)
0
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 происходит хреновина. ПРОБЛЕМА НЕ В ЛОГИКЕ ВЫЧИСЛЕНИЯ ЭПСИЛОН. ПРОБЛЕМА В СТРАННОМ ПРЕОБРАЗОВАНИИ ТИПА, КОТОРОГО НЕ ДОЛЖНО БЫТЬ, НО ПРОИСХОДИТ.

Люди, вы чего? Уже второй чудесатый "ответ" в теме. Да с каким гонором-то. Жара что ли так действует?
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,523
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 Посмотреть сообщение
Да с каким гонором-то.
где ты гонор то увидел?
0
7 / 11 / 0
Регистрация: 01.08.2012
Сообщений: 99
09.08.2012, 23:46  [ТС] 16
ValeryS, мир.

Так чё с типами-то? Диавольщина какая-то
0
Заблокирован
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#
0
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.
0
Заблокирован
10.08.2012, 20:34 19

Не по теме:

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



Добавлено через 11 минут
kozlik_kozlik, есть имхо. в первом примере сравниваются две переменные встроенных типов, а во втором примере результат арифметической операции (скорее всего уложенный в long double) с переменной, которая автоматически приводится к большему типу.
0
10.08.2012, 20:34
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.08.2012, 20:34
Помогаю со студенческими работами здесь

Баг компилятора или я дурак?
До:https://www.cyberforum.ru/attachment.php?attachmentid=840160&amp;stc=1&amp;d=1496427343...

Что-то интересное. Или программа, которая принимает либо 1, либо 2 числа
Программа - консольное приложение, в качестве параметров при вызове принимает одно или два целых...

Либо я дурак либо лыжи не едут
Процессор intel core i7 4790 Видеокарта Видеокарта GIGABYTE GeForce GTX 1070 8g оперативка 16...

Баг или я дурак =)
Подскажите что делаю не так. в классе Base создаю объект класса Pacinet. Создается ошибок...


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

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru