Форум русскоязычного сообщества Ubuntu


Считаете, что Ubuntu недостаточно дружелюбна к новичкам?
Помогите создать новое Руководство для новичков!

Автор Тема: Новогодние чудеса от С++  (Прочитано 833 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Jack Sparrow

  • Автор темы
  • Активист
  • *
  • Сообщений: 641
    • Просмотр профиля
Новогодние чудеса от С++
« : 01 Января 2015, 17:38:30 »
Нет, все-таки C/C++ способны довести человека до отчаяния. Что происходит? Есть, казалось бы, элементарный цикл для вывода чисел:
Код: (C) [Выделить]
#include <iostream>
using namespace std;

int main()
{
    for (double x = 1; x <= 7; x += 0.1)
        cout << x << endl;
   
    return 0;
}
 
Выводит числа от 1 до 7 включительно с шагом 0.1. Все понятно. Но если в условии x <= 7  поменять 7 скажем, на 3, то числа уже будут выводиться не до 3, а до 2.9. То же самое с 4 - выводит до 3.9.
С цифрами 5, 6, 7, 8, 9, 10 и т.п. выводит как задумано, т.е. включительно. Не знаю, где там происходит перелом, но если поставить 70, то опять будет выводиться до 69.9.

Интересно, если поменять double на float, то и 3, и 4 и т.п. будут выводиться нормально (но не 2: при двойке выводится до 1.9). Причем с float и x <= 70 интересно еще то, что в некоторых местах числа выводятся с точностью до десятых (как, собственно, и должно быть, ведь приращение идет по 0.1), но в некоторых местах с точностью до десятитысячных (например, 25.5001).

В чем тут вообще дело? Как разобраться с этими типами? Вроде бы значения не выходят за рамки разрядности, так в чем же дело? И, самое интересное, почему в одном случае так, а в другом эдак? Если бы было все правильно, или все неправильно, то было бы понятнее. А так - что это?
Нейросети тебя не заменят. Тебя заменит человек, который умеет ими пользоваться.

Оффлайн SergeyIT

  • Зануда.
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 5744
  • Все по палатам!
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #1 : 01 Января 2015, 18:39:53 »
Число с плавающей запятой
Сравнивать числа с плавающей запятой == < > неправильно.
« Последнее редактирование: 01 Января 2015, 19:24:50 от chemtech »
Извините, я все еще учусь

Оффлайн Jack Sparrow

  • Автор темы
  • Активист
  • *
  • Сообщений: 641
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #2 : 01 Января 2015, 20:11:27 »
Но в статье ничего не говорится про правильно или не правильно.
Почитал еще другие статьи, 1 и 2, и понял, что ... ничего не понял. Не хочу слишком сильно в теорию углубляться, там можно мозг сломать. Просто хочу понять: как тогда быть в подобных случаях?


Интересно, что подобная задача была задана на первом курсе приборостроительного факультета (т.е. программирование там не главное). Нужно было что-то подсчитать по формуле и вывести диапазон: формула * коэффициент. А коэффициент меняется от 1 до 3 с шагом 0.1.
Нейросети тебя не заменят. Тебя заменит человек, который умеет ими пользоваться.

Оффлайн SergeyIT

  • Зануда.
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 5744
  • Все по палатам!
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #3 : 01 Января 2015, 20:23:08 »
Интересно, что подобная задача была задана на первом курсе приборостроительного факультета (т.е. программирование там не главное).
Приборы сейчас, кстати, практически все цифровые и измеряют не целые величины - это же основы
Извините, я все еще учусь

Оффлайн Protopopulus

  • Старожил
  • *
  • Сообщений: 1695
  • А чего вы так смотрите?..
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #4 : 01 Января 2015, 20:30:11 »
Интересно, что подобная задача была задана на первом курсе приборостроительного факультета (т.е. программирование там не главное). Нужно было что-то подсчитать по формуле и вывести диапазон: формула * коэффициент. А коэффициент меняется от 1 до 3 с шагом 0.1.

Делай так:
for(int i = 0; i <= 30; i++) {
    (что-то * i) / 10.0;
}
Если ты владеешь знаниями, то и знания владеют тобой. (с) Protopopulus

Оффлайн peregrine

  • FSM
  • СуперМодератор
  • Старожил
  • *
  • Сообщений: 7215
  • Gentoo x64 Ubuntu 16.04.1 x64
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #5 : 01 Января 2015, 20:36:07 »
Jack Sparrow, корректнее всего в таких случаях умножить всё на 10. Т.е.
Код: (cpp) [Выделить]
#include <iostream>
using namespace std;
 
int main()
{
    for (double x = 10; x <= 70; x += 1)
        cout << x/10 << endl;
   
    return 0;
}
Происходит так из-за того, что числа с плавающей точкой, а не с фиксированной. Если же надо именно с дробными числами, то так тоже можно, при условии, что ты посчитал погрешность delta, тогда ты можешь сравнивать числа с плавающей точкой как-то так (хотя и это не совсем верно, тут надо вспоминать сколько знаков значащие):
Код: (cpp) [Выделить]
double x=1.5;
double y=1.6;
double delta=0.05;//устраивающая тебя погрешность
if((x-y)(x-y)<delta*delta)//можно и оптимизировать этот кусочек, но тогда погрешность твоя должна быть в квадрате, а вообще современный компилятор должен это сам развернуть.
{

}
else
{

}
« Последнее редактирование: 01 Января 2015, 20:39:07 от peregrine »

Оффлайн Protopopulus

  • Старожил
  • *
  • Сообщений: 1695
  • А чего вы так смотрите?..
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #6 : 01 Января 2015, 20:42:19 »
peregrine, слишком сложно. Гораздо проще и рациональнее, в таких случаях, использовать целочисленный инкремент в качестве аргумента. Просто подбирается пара чисел "предел"/"шаг аргумента".
Если ты владеешь знаниями, то и знания владеют тобой. (с) Protopopulus

Оффлайн Jack Sparrow

  • Автор темы
  • Активист
  • *
  • Сообщений: 641
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #7 : 01 Января 2015, 21:39:25 »
Наверное, для простоты нужно тогда так делать, чтобы не запутаться:
 
Код: (C) [Выделить]
#include <iostream>
using namespace std;

int main()
{
    int i, from, to;
    from = 1;
    to = 3;
   
    for(i = from * 10; i <= to * 10; i++)
        cout <<  i / 10.0 << endl;
   
    return 0;
}
 
Нейросети тебя не заменят. Тебя заменит человек, который умеет ими пользоваться.

Оффлайн spk-ubuntu

  • Активист
  • *
  • Сообщений: 502
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #8 : 02 Января 2015, 01:10:25 »
учитывая, что погрешность в каком-нибудь десятом знаке после запятой, можно написать что-то вроде
for ( double x = 1 ; x <= 7.05; x += 0.1 )

Оффлайн peregrine

  • FSM
  • СуперМодератор
  • Старожил
  • *
  • Сообщений: 7215
  • Gentoo x64 Ubuntu 16.04.1 x64
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #9 : 02 Января 2015, 05:58:37 »
spk-ubuntu, нельзя, т.к. число 3 будет представлено, как 2,9999999999. Потому либо на delta наращивать результат, до которого выводить, либо, что лучше - использовать целые числа.

Оффлайн MEJIOMAH17

  • Любитель
  • *
  • Сообщений: 87
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #10 : 02 Января 2015, 10:55:20 »
Наверное зависит от комплятора или системы, но в gcc под 32 битную архетек. все работает нормально (7 выводит)
Я бы все таки на всякий случай указывал 7.0 дабы сравнивал с даблом а не с интом

Оффлайн peregrine

  • FSM
  • СуперМодератор
  • Старожил
  • *
  • Сообщений: 7215
  • Gentoo x64 Ubuntu 16.04.1 x64
    • Просмотр профиля
Re: Новогодние чудеса от С++
« Ответ #11 : 02 Января 2015, 17:15:16 »
MEJIOMAH17, поставь вместо 7 - 3 и посмотри на результат.

 

Страница сгенерирована за 0.024 секунд. Запросов: 23.