Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> математическая ошибка при прохождении цикла 
V
    Опции темы
nubliK
Дата 20.1.2009, 02:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


вселенские матрицы



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 11.9.2008
Где: Владивосток

Репутация: нет
Всего: нет



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

int someFunc(float A)
  {
      int n = 0;
      while(A > 6)
      {
         A = A - 0.1;
         n++;
      }
   return n;
   }


Компилится все правильно и работает тоже (в данном примере функция немного отличается от оригинала), дык вот если числу "A" задать значение больше 13 то цикл начинает врать на еденицу - как побороть?
PM MAIL ICQ   Вверх
NightmareZ
Дата 20.1.2009, 02:19 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


[хакер]
**


Профиль
Группа: Участник
Сообщений: 699
Регистрация: 10.8.2006

Репутация: 0
Всего: 13



Цитата(nubliK @  20.1.2009,  02:11 Найти цитируемый пост)
как побороть?


Приведённый тобой код можно заменить на такой:

Код

int someFunc(float A)
{
  return A * 60;
}


И никакой цикл тебе врать ничего не будет.


--------------------
NightmareZ.net - мой блог и сайт, мои проекты и прочий трэш
Ely-Art.ru - наша маленькая домашняя арт-студия
mugcraft.ru - кружки на любой вкус
PM WWW ICQ Skype GTalk AOL YIM   Вверх
mes
Дата 20.1.2009, 02:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(nubliK @  20.1.2009,  01:11 Найти цитируемый пост)
то цикл начинает врать на еденицу - как побороть? 

скорей всего из за ошибки округления цифр с плавающей запятой. 
исправьте цикл на абсолютный расчет или избавьтесь от плавающих значений.


Цитата(NightmareZ @  20.1.2009,  01:19 Найти цитируемый пост)
  return A * 60;

хм... непонятно как из примера ТС, Вы получили такой код


--------------------
PM MAIL WWW   Вверх
nubliK
Дата 20.1.2009, 04:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


вселенские матрицы



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 11.9.2008
Где: Владивосток

Репутация: нет
Всего: нет



Цитата(NightmareZ @ 20.1.2009,  02:19)
Цитата(nubliK @  20.1.2009,  02:11 Найти цитируемый пост)
как побороть?


Приведённый тобой код можно заменить на такой:

Код

int someFunc(float A)
{
  return A * 60;
}


И никакой цикл тебе врать ничего не будет.

Бред сивой кобылы мягко говоря. Смотри код внимательно.
Цитата(mes)

скорей всего из за ошибки округления цифр с плавающей запятой. 
исправьте цикл на абсолютный расчет или избавьтесь от плавающих значений.


Как это сделать? и переменная обязательно должна быть с плавающей точкой. Вычитаемое может быть и не 0.1 но и 0.05 и хоть десять.

Добавлено через 12 минут и 55 секунд
прошу прощение за грубость у NightmareZ =)

Это сообщение отредактировал(а) nubliK - 20.1.2009, 04:22
PM MAIL ICQ   Вверх
nubliK
Дата 20.1.2009, 06:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


вселенские матрицы



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 11.9.2008
Где: Владивосток

Репутация: нет
Всего: нет



нашел небольшую статейку по теме тут http://xpoint.ru/know-how/Articles/Floatin...umbers?comments
но вопрос остался в силе =)
И еще если это никого не затруднит не могли бы вы привести пример варианта как можно задать точность округления числа с плавающей точкой (то есть точность до определенного знака).
PM MAIL ICQ   Вверх
ksili
Дата 20.1.2009, 06:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: нет
Всего: 17



Можно использовать числа с плавающей точкой двойной точности - тип double. Или в крайнем случае - расширенной точности (long double).
Указать точность округления до определенного знака при вычислениях не получится.


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Kurganec
Дата 20.1.2009, 07:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 6.6.2008
Где: СПБ

Репутация: нет
Всего: нет



попробуй while(A > 6.)  //с точкой
или while(A>6.*0.99999) // близкий к  100%

последнее конечно бред, но у меня тоже проблемы в своё время были при сравнении вещественных переменных, с целыми.
отпишись тока  smile  cсамому интересно.

PM MAIL ICQ Skype   Вверх
nubliK
Дата 20.1.2009, 07:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


вселенские матрицы



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 11.9.2008
Где: Владивосток

Репутация: нет
Всего: нет



Всем огромное спасибо, вот мое решение получилось так:

Код

int someFunc(double A) //изменил тип - потому что мне его достаточно
  {
      int n = 0;
      while(A > 6)
      {
         A =(float)A - 0.1; //преобразовал тип
         n++;
      }
   return n;
   }


Получается что компу нехватает точности чтобы хранить число с плавающей точкой - соответственно решение получилось через приведение типов от double к float =)

Если кто придумает правельнее то ХАЧУ!
кстати тут вот подобная дисскуссия вилась и слизал идею я отсюда http://forum.codenet.ru/archive/index.php/t-24605.html
PM MAIL ICQ   Вверх
vinter
Дата 20.1.2009, 08:52 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 8
Всего: 56



Код

float epsilon = 0.000001;
while((A - epsilon) > 6)
{
   A -= 0.1;
  n++;
}


Это сообщение отредактировал(а) vinter - 20.1.2009, 09:43


--------------------
Мой блог
PM MAIL WWW   Вверх
maxim1000
Дата 20.1.2009, 09:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 1
Всего: 110



а если так: smile
Код

int someFunc(float A)
  {
      int n = 0;
      while(A > 6)
      {
         A = A - 0.25;
         n++;
      }
   return n;
   }

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

Добавлено через 1 минуту и 3 секунды
Цитата(vinter @  20.1.2009,  08:52 Найти цитируемый пост)
float epsilon = 0.000001;
while((A - epsilon) > 6)
  n++;

что-то здесь забыто: цикл либо не выполнится (если условие изначально ложное), либо будет бесконечным


--------------------
qqq
PM WWW   Вверх
vinter
Дата 20.1.2009, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 8
Всего: 56



maxim1000, спасибо, исправил


--------------------
Мой блог
PM MAIL WWW   Вверх
nubliK
Дата 20.1.2009, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


вселенские матрицы



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 11.9.2008
Где: Владивосток

Репутация: нет
Всего: нет



А вот и правильный ответ:

Код

int someFunc(float A)
  {
      int B = static_cast<int>(A*10)  //множитель "10" можно менять в зависимости от значения вычитаемого, static_cast<int> - уходим от типа с плавающей точкой.
      int n = 0;
      while(A > 60) //не забываем про множитель.
      {
         B = B - 1; //не забываем про множитель и вычитаемое.
         n++;
      }
   return n;
   }


Спасибо товарищу mes т.к. он прав что в таких случаях лучший вариант уйти от плавающей точки.
smile  
PM MAIL ICQ   Вверх
baldina
Дата 20.1.2009, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



mes:
Цитата

исправьте цикл на абсолютный расчет

 smile 

данный случай настолько прост, что его даже обсуждать не стоит: здесь вообще цикл не нужен.

а вот если он нужен, то, например, вместо

Код

double a = ..., b = ...;
int n = ...;

double step = (b-a)/n;
for (double x = a; x <= b; x += step)
{
   cout << f(x);
}


делаем

Код

double a = ..., b = ...;
int n = ...;

double step = (b-a)/n;
for (int i=0; i < n; ++i)
{
   double x = a+i*step;
   cout << f(x);
}


сравнение чисел с плавающей можно производить так:
Код

namespace impl {

  template <typename T, bool>
  struct is_equal {
    bool operator ()(T x, T y, T Epsilon);
  };

  template <typename T>
  struct is_equal<T,true> {
    bool operator ()(T x, T y, T) { return x==y; }
  };

  template <typename T>
  struct is_equal<T,false> {
    bool operator ()(T x, T y, T epsilon) { 
      if (x==y)
        return true;
      using namespace std;
      return abs (x-y) / max (abs(x), abs(y)) < epsilon;
    }
  };

} // namespace impl

template <typename T>
bool is_equal (T x, T y, T Epsilon = pow (10.0,-std::numeric_limits <T>::digits10))
{
  impl::is_equal <T, std::numeric_limits <T>::is_exact> is_eq;
  return is_eq (x, y, Epsilon);
}

PM MAIL   Вверх
GoldFinch
Дата 20.1.2009, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 6
Всего: 26



Цитата(maxim1000 @  20.1.2009,  09:31 Найти цитируемый пост)
те, которые в двоичном виде представляются в виде конечных (и не очень длинных) дробей, по идее, должны представляться точно, хотя это уже похоже на деталь реализации, к которой не стоит привязываться...

неужели троичные машины всетаки появятся?
PM MAIL ICQ   Вверх
baldina
Дата 20.1.2009, 19:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



они уже давно появились. некоторых еще на свете не было  smile 
http://chernykh.net/content/view/236/252/

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0646 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.