2016-10-12 7 views
-1

Я знаю, что плавающие точки в C не очень точны. Но у меня есть снайпер, где я не понимаю, почему я получаю такие результаты. Во-первых, если я вычисляю в одной строке, я получаю неправильный результат «0». Просто, если я разделил те же вычисления на несколько команд, я получаю почти то, что ожидаю.C math lib - просчеты с плавающей точкой?

Так первые вопросы:

  1. Почему одна строка отличается от расщепленных линий?
  2. Есть ли способ, как рассчитать более точный способ? Я имею в виду, что 320- (10,44 * 4) должны быть 278,24, а не 278,23999! Я понимаю проблемы округления при числе, например, корнях или пи. Но не в приведенном выше примере.

Ok, вот мой код (минимизируется sniplet):

#include <math.h> 
#include <stdio.h> 

float kurv_steil, 
     kurv_korr, 
     t_abl_s, 
     t_out, 
     t_abl_s, 
     b, 
     t_tank_s; 

void main() 
{ 
    t_tank_s=32; 
    kurv_steil=0.85; 
    kurv_korr=-5; 
    t_out=1.44; 
    t_abl_s=24; 

    printf("Werte: k_steil: %f k_korr: %f t_out: %f t_abl_s: %f\n",kurv_steil,kurv_korr,t_out,t_abl_s); 
    b= pow(t_abl_s,(t_out/(320-(t_out*4))))*0.65*kurv_steil*b*(-t_out+20); 

    printf("[temp] Ganze Rechnung tank_s: %f\n",b); 
    b=320-(t_out*4); 

    printf("[temp] 320-(t_out*4) b: %f\n",b); 
    b=t_out/b; 

    printf("[temp] t_out/b b: %f\n",b); 
    b=pow(t_abl_s,b); 

    printf("[temp] t_abl_s^b b: %f\n",b); 
    b=0.65*kurv_steil*b; 

    printf("[temp] 0.65*kurv_steil*b b: %f\n",b); 
    b=b*(-t_out+20); 

    printf("[temp] b*(-t_out+20) b: %f\n",b); 
    b=2*b+t_abl_s+kurv_korr; 

    printf("[temp] 2*b*(-t_abl_s) b: %f\n",b); 
} 

Выход:

Werte: k_steil: 0.850000 k_korr: -5.000000 t_out: 1.440000 t_abl_s: 24.000000 
[temp] Ganze Rechnung tank_s: 0.000000 
[temp] 320-(t_out*4) b: 314.239990 
[temp] t_out/b b: 0.004582 
[temp] t_abl_s^b b: 1.014670 
[temp] 0.65*kurv_steil*b b: 0.560605 
[temp] b*(-t_out+20) b: 10.404831 
[temp] 2*b*(-t_abl_s) b: 39.809662 

Я бы ожидать, чтобы иметь первый выход имеют одинаковое значение "39.809662" , но всегда имеет значение «0». Зачем?

+1

Отклоните свой код до того, как опубликовать его и напишите на английском, чтобы люди могли понять что-то еще. – LPs

+1

Подпись для main может быть: 'int main (void)' или 'main (int argc, char * argv [])' – LPs

+0

Простая вещь, которую вы можете сделать, это изменить форматирование для печати чисел, а не пытаться использовать '% f' '% .3f' или'% 6.3f'. Математика в C очень точная, более того, результаты не всегда кажутся красивыми в десятичных знаках. –

ответ

0

как сказано выше, проблема в формуле вы используете. У вас есть b=... *b*.... На данный момент b имеет неизвестное значение (скорее всего, компилятор установил его в 0), поэтому у вас есть b=...*0*..., что делает конечный результат 0.

Также следует добавить 2* ... + t_abl_s+kurv_korr к вашей формуле

Таким образом, формула будет выглядит как

b= 2 * 
    pow(t_abl_s,(t_out/(320-(t_out*4)))) * 
    0.65 * kurv_steil * 
    (-t_out+20) + 
    t_abl_s + kurv_korr; 
4

В этой строке

b= pow(t_abl_s,(t_out/(320-(t_out*4))))*0.65*kurv_steil* b *(-t_out+20); 

вы используете переменную Ъ на правой стороне. Обычно это будет нулевым при запуске программы, поэтому любое умноженное на него значение будет равно нулю. Не полагайтесь на переменную, имеющую определенное значение, всегда инициализируйте свои переменные.

+1

С каких это пор, когда он обычно равен нулю? Он не определен, и я бы предположил, что он не равен нулю чаще, чем он есть. Твердый ответ, он просто звучит так тривиально, что его серьезная ошибка. –

+3

@KamiKaze В этом случае переменная объявляется в области файлов, то есть имеет статическую продолжительность хранения и поэтому всегда равна нулю. Гарантируется стандартом C, поэтому ответ правильный, кроме «типично» - он будет равен нулю. Тем не менее, плохой практикой является создание программ, основанных на нулевой инициализации переменных статической продолжительности хранения. – Lundin

+0

@ Lundin Прояснение очень ценится. –

0

Как вы можете видеть в этой ссылке, 1,44 не могут быть представлены в двоичной системе:

http://www.wolframalpha.com/input/?i=1.44+in+binary

Поэтому любые точечные вычисления с плавающей вы делаете с ним будет неточным.

Более знакомый пример - попытаться представить 1/3. В base3 это просто 0,1. В десятичной форме это 0.33333 ... Это та же идея с любым десятичным числом, заканчивающимся на .44. Он не может быть точно представлен в двоичном формате.

0

Спасибо, ребята!

О, мужчина! Я был таким глупым. Да, действительно, в формуле была «* b», результатом которой было «0» все время, поскольку b не инициализировалось ранее (и, очевидно, случайным всегда ноль).

Что касается точности вычислений, я не уверен, поскольку 278.24 это не то же самое, что и 278.23999. С другой стороны, теперь это работает для меня.

Спасибо!

+0

Как только вы используете плавающую точку, вы обязательно будете иметь ошибки. Это ваш долг держать их на низком уровне. Из-за этого вы не сравниваете float с ==. Например, попробуйте 0.1 + 0.1 + 0.1 == 0.3, это должно быть ложным. –