2015-11-12 2 views
0

Вот мой код:C++ Modulus возвращение неправильного ответа

#include <iostream> 
#include <cmath> 
using namespace std; 

int main() 
{ 
    int n, i, num, m, k = 0; 
    cout << "Enter a number :\n"; 
    cin >> num; 
    n = log10(num); 

    while (n > 0) { 
     i = pow(10, n); 
     m = num/i; 
     k = k + pow(m, 3); 
     num = num % i; 
     --n; 
     cout << m << endl; 
     cout << num << endl; 
    } 
    k = k + pow(num, 3); 
    return 0; 
} 

Когда я вход 111 это дает мне это

1 
12 
1 
2 

Я использую CodeBlocks. Я не знаю, что не так.

+1

Похоже, вам, возможно, потребуется научиться использовать отладчик для перехода через ваш код. С хорошим отладчиком вы можете выполнить свою программу по очереди и посмотреть, где она отклоняется от ожидаемого. Это важный инструмент, если вы собираетесь заниматься программированием. Дальнейшее чтение: ** [Как отлаживать небольшие программы] (http://ericlippert.com/2014/03/05/how-to-debug-small-programs/) ** – NathanOliver

+1

СОВЕТ: 'int'! =' Double ' –

+3

вместо того, чтобы сказать, что C++ mod возвращает неверный ответ, может быть более разумным сказать, что мода не возвращает ожидаемого ответа. Небеса запрещают вам находить ошибку в моде после всех этих лет. : D – therainmaker

ответ

2

Всякий раз, когда я использую pow, ожидающий целочисленный результат, я добавляю .5, поэтому я использую (int)(pow(10,m)+.5) вместо того, чтобы компилятор автоматически конвертировал pow(10,m) в int.

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

Если это имеет значение, это разница, которую вы хотите. Если это не имеет значения, у него была крошечная стоимость.

В опубликованном коде я бы отрегулировал каждый вызов до pow таким образом, а не только тот, который я использовал в качестве примера.

Нет одинаково простого решения для использования log10, но это может быть проблема. Поскольку вы ожидаете не целого ответа и хотите, чтобы не целочисленный ответ усекался до целого числа, добавление .5 было бы очень неправильным. Поэтому вам может потребоваться найти более сложную работу для фундаментальной проблемы работы с плавающей точкой. Я не уверен, но, предполагая 32-битные целые числа, я думаю, что добавление 1e-10 к результату log10 до того, как преобразование в int оба никогда не будет достаточно, чтобы изменить log10(10^n-1) на log10(10^n), но всегда достаточно, чтобы исправить ошибку, которая могла бы сделать обратное.

0

powс плавающей запятой возведение в степень.

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

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

Это особенно проблематично, когда вы преобразовать результат в целое число, так как результат усекается до нуля: int x = 0.999999; комплект x == 0, а не x == 1. Даже самая маленькая ошибка в неправильном направлении полностью портит результат.

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


Если вы хотите сделать точно, целочисленная арифметика, то вы должны использовать функции, которые делают это. например напишите свою собственную функцию ipow, которая вычисляет целочисленное возведение в степень без каких-либо операций с плавающей запятой.

+0

Есть более сложные ситуации, в которых я бы согласился с вами. Но на уровне этого вопроса, я думаю, лучше подумать, что 64-разрядная «двойная» достаточно для операций с 32-битными целыми числами, если вы используете немного дополнительную осторожность и думаете о конверсиях (плюс немного позаботиться и подумать, чтобы убедиться, что вы действительно работаете с 'double' и с 32-битным' int'). – JSF

+0

В нескольких вопросах в SO я видел (и иногда помогал) использование 'double' для log и pow из 64-битных целых чисел. 'double' в основном недостаточно хорош для этой работы. Но в конкретных целях он все же лучше подходит, используя 'double' и компенсируя ошибку, по сравнению с выполнением задания с нуля с более точным представлением. – JSF

+0

Хотя я согласен с общими предложениями в этом ответе, говоря: «Никогда не опираться на них», это слишком далеко. после утверждения типа 'x = 12.0 * 13.0;' x всегда _exactly_ равно 156; ошибок округления нет. Правда, вам нужно немного узнать о IEEE (такие мелочи, как «float могут представлять все целые числа до 16777216 без потери точности», хорошо знать), но это не значит, что вы не можете использовать плавающие точки, если не знаете все входы и выходы спецификаций. –

Смежные вопросы