double, float, {0.0}, {0.0f}, в чем дело? - PullRequest
1 голос
/ 10 июля 2020

Итак, я написал эту небольшую практическую программу, которая сообщает вам, сколько никелей и центов вам потребуется на указанную сумму. Я не понимаю, почему программа выводит 0 за центы, даже если математика верна. Я не могу понять, в чем проблема.

// Example program
#include <iostream>

using namespace std;

int main()
{
    const double nickels{0.05};
    const double cents{0.01};
    int amt_needed_nickels{0}, amt_needed_cents{0};
    double amt_val{0.06f}; // for 0.06 cents
    double amt_val_copy{amt_val};
    
    amt_needed_nickels = amt_val / nickels;
    if(amt_needed_nickels != 0)
        amt_val -= (nickels * amt_needed_nickels);
    amt_needed_cents =  amt_val / cents;
    
    cout << "If it costs $" << amt_val_copy << ", you'll need:\nNickels: " << amt_needed_nickels << "\nCents: " << amt_needed_cents << "\n";
    cout << "Even though amt_val is " << amt_val << ", and cents is also " << cents << ", and 0.01/0.01 does equal 1, why is amt_needed_cents not 1?\n";
}

Честно говоря, я знаю, изменяю ли я const double cents {0,01} на const float cents {0,01} и удаляю f из double amt_val {0,06f}; удвоить amt_val {0,06}; это сработает, но я не понимаю, что на самом деле происходит под поверхностью. Почему программа дает 0 для amt_needed_cents, указанного выше, и 1 для другого cenario?

// Example program
#include <iostream>

using namespace std;

int main()
{
    const double nickels{0.05};
    const float cents{0.01};
    int amt_needed_nickels{0}, amt_needed_cents{0};
    double amt_val{0.06}; // for 0.06 cents
    double amt_val_copy{amt_val};
    
    amt_needed_nickels = amt_val / nickels;
    if(amt_needed_nickels != 0)
        amt_val -= (nickels * amt_needed_nickels);
    amt_needed_cents =  amt_val / cents;
    
    cout << "If it costs $" << amt_val_copy << ", you'll need:\nNickels: " << amt_needed_nickels << "\nCents: " << amt_needed_cents << "\n";
    cout << "I know this is correct, but I don't know what the compiler is thinking with this as compared to the other\n\n";
}


Ответы [ 2 ]

4 голосов
/ 10 июля 2020

Вычисления с плавающей запятой неточны, при математических вычислениях вы получаете очень маленькую разницу, которая нарушит вашу программу, если вы попытаетесь проверить точное равенство чисел. Например, 1.2 * 3 не совсем 3.6 (обратите внимание, что это не означает, что все вычисления неточны: например, умножение на любую степень 2 всегда точно: такие вещи, как 1.5 * 2 и 1.1 / 4 всегда дает наилучший возможный ответ). Это связано с тем, что десятичные дроби, такие как 1/10 и 1/100, не могут быть точно представлены в двоичном формате, что является проблемой, когда наши монеты основаны на 1/100 (центах).

В вашей программе вы должны вместо этого представляйте монеты как целые числа, конвертируя все значения в центы, тогда все будет работать нормально. То есть вы знаете, что наибольший знаменатель, с которым вам когда-либо приходилось иметь дело, равен 100, так что вы можете все умножить на 100. Итак, nickels будет 5, cents будет 1, и все расчеты будут точными.

Чтобы избежать путаницы, вот ваш код в целых числах:

int dollars = 100, nickels = 5, cents = 1;

int amt_needed_dollars = amt_val / dollars;
amt_val -= amt_needed_dollars * dollars;
int amt_needed_nickels = amt_val / nickels;
amt_val -= amt_needed_nickels * nickels;
// skipped dividing by cents, because it's '1' anyway
int amt_needed_cents = amt_val;
0 голосов
/ 10 июля 2020
  • Float: число с плавающей запятой. Это 32-битное число с одинарной точностью. Чаще встречается.
  • Double: Как и в названии, он содержит "двойное" значение числа с плавающей запятой. Это 64-битное число двойной точности. Он более точен и может содержать способ больше десятичных знаков.

Я не лучший специалист в C ++, но похоже, что проблема здесь:

int amt_needed_nickels{0}, amt_needed_cents{0};
amt_needed_nickels = amt_val / nickels;

Попробуйте изменить amt_needed_cents на float или удвойте анализ / округление позже. В отличие от других языков (например, JS) c ++ раздражает при попытке преобразовать подобные типы. Вы делите два числа с плавающей запятой на int, который, вероятно, усекает десятичное число.

...