Я был почти уверен, что делаю это правильно, но, видимо, нет. Этот цикл while работает бесконечно, как только он достигает 0. Он снова и снова выводит «Ежемесячный платеж: 0,00 долл. США» и «Ваш кредит после этого платежа: 0,00 долл. США». Что я делаю неправильно?
while (loan_balance ! = 0)
{
monthly_payment = loan_balance / 20;
loan_balance = loan_balance - monthly_payment;
cout << "Monthly Payment: $" << monthly_payment << ends;
cout << "Your loan balance after that payment is: $" << loan_balance << endl;
}
Если load_balance
тип с плавающей запятой (float
или же double
), затем load_balance != 0
(где 0
является 0.0f
), вероятно, никогда не будет ложным, если явно не установлено load_balance = 0.0f
, Таким образом, вместо этого следует сравнить с небольшим порогом, например,
while(load_balance >= 1e-4)
Также оператор неравенства !=
с пробелом ! =
это не работает.
loan_balance — это, вероятно, float или double; это может уменьшиться, чтобы быть чем-то близким, но не совсем 0. Измените свое сравнение на «> 0».
0 тип данных типа int
0.0f тип данных типа double
или же float
Так ты говоришь
while(loan_balance != 0)
do stuff
Компилятор в ответ говорит:loan_balance
никогда Когда-либо быть 0 если это дабл / поплавок, так что я просто буду продолжать делать вещи «.
Имейте в виду: целые числа не являются числами с плавающей точкой или двойными
Скорее всего, ваш loan_balance никогда не будет точно равен 0. Я уверен, что вы хотите, чтобы ваш loan_balance был в плавающем или двойном размере.
double loan_balance=23000.00;
while (loan_balance >0.000)
{
monthly_payment = loan_balance / 20.0;
loan_balance = loan_balance - monthly_payment;
cout << "Monthly Payment: $" << monthly_payment << ends;
cout << "Your loan balance after that payment is: $" << loan_balance << endl;
}
Вы столкнулись с проблемой точности и округления.
Когда вы экспоненциально уменьшите число, оно будет сходиться к нулю. Если это число с плавающей запятой ограниченной точности, то число будет настолько малым, что его невозможно будет отличить от нуля при любом возможном представлении. Итак, петля
double d=1.0; // or some other finite value
while(d!=0.0)
d*=ratio; // ratio is some finite value so that fabs(ratio)<1.0
закончил бы в конечном числе итераций.
Тем не менее, в зависимости от значений d
а также ratio
, особенно когда d
приближается к нулю в субнормальном диапазоне (подразумевает меньшее количество значащих бит) и fabs(ratio)
близко к 1,0 (медленная сходимость), выбранный режим округления может вызвать d*ratio
округляться в сторону d
, Когда это произойдет, цикл выше никогда не закончится.
В машинах / компиляторах, которые поддерживают IEC 60559, вы должны быть в состоянии проверить и установить режим округления с плавающей запятой, используя fegetround()
а также fesetround()
(объявлено в <fenv.h>
). Вероятно, что округление по умолчанию в вашей системе является ближайшим. Чтобы цикл выше сходился быстрее (или вообще), было бы лучше, чтобы округление было к 0.
Тем не менее, обратите внимание, что это связано с ценой: в зависимости от приложения изменение режима округления может быть нежелательным с точки зрения точности / точности (OTOH, если вы уже работаете в субнормальном диапазоне, ваша точность, вероятно, уже не так хороша) ,
Но проблема сходимости исходного вопроса все еще немного сложнее, потому что это делается с помощью двухэтапной операции. Таким образом, в операции деления есть одно округление, а в вычитании — другое. Чтобы увеличить вероятность и скорость сходимости, вычитание должно занять как можно больше loan_balance
ценность как можно, поэтому может быть округление было бы лучше в этом случае. На самом деле, когда я добавил fesetround(FP_UPWARD)
к исходному коду ОП (вместе с определением начального значения loan_balance
в 1.0
) он сходится после 14466 итераций. (Обратите внимание, что это всего лишь предположение, и эффект на исходный код мог быть просто особым условием. Для его оценки потребуется более глубокий анализ, и такой анализ должен учитывать различные значения отношения, а также относительное величие вычитания и вычитания.)