Цель-C: Странный результат расчета - PullRequest
0 голосов
/ 12 июля 2011

Я изучаю Objective-C, выполнил простую программу и получил неожиданный результат.Эта программа - просто тест таблицы умножения ... Пользователь вводит количество итераций (тестовых вопросов), а затем вводит ответы.Это после того, как программа отображает количество правильных и неправильных ответов, процент и принятый / неудачный результат.

#import <Foundation/Foundation.h>

int main (int argc, const char * argv []) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Welcome to multiplication table test");
int rightAnswers; //the sum of the right answers
int wrongAnswers; //the sum of wrong answers
int combinations; //the number of combinations@


NSLog(@"Please, input the number of test combinations");
scanf("%d",&combinations);

for(int i=0; i<combinations; ++i)
{
    int firstInt=rand()%8+1;
    int secondInt=rand()%8+1;
    int result=firstInt*secondInt;
    int answer;


    NSLog(@"%d*%d=",firstInt,secondInt);
    scanf("%d",&answer);
    if(answer==result)
    {
        NSLog(@"Ok");
        rightAnswers++;
    }
    else
    {
        NSLog(@"Error");
        wrongAnswers++;
    }
}
int percent=(100/combinations)*rightAnswers;
NSLog(@"Combinations passed: %d",combinations);
NSLog(@"Answered right: %d times",rightAnswers);
NSLog(@"Answered wrong: %d times",wrongAnswers);
NSLog(@"Completed %d percent",percent);
if(percent>=70)NSLog(@"accepted");
else
    NSLog(@"failed");
[pool drain];
return 0;

}

Проблема (странный результат)

Когда я ввожу 3 итерации и отвечаю правильно, я не получаю 100% правильно.Получаю только 99%.То же количество я пробовал на своем калькуляторе iPhone.

100/3 = 33,3333333 ... процент за один правильный ответ (программа отображает 33%. Цифры после обрезания мантиссы)

33.3333333... * 3 = 100%

Может кто-нибудь объяснить мне, где я ошибся?Thanx.

Ответы [ 4 ]

3 голосов
/ 12 июля 2011

Это результат целочисленного деления. При выполнении деления между двумя целочисленными типами результат автоматически округляется до 0, чтобы сформировать целое число. Таким образом, целочисленное деление (100 / 3) дает результат 33, а не 33,33 .... Когда вы умножите это на 3, вы получите 99. Чтобы исправить это, вы можете форсировать деление с плавающей запятой, изменив 100 на 100.0 , .0 сообщает компилятору, что он должен использовать тип с плавающей запятой вместо целого числа, вызывая деление с плавающей запятой. В результате округление не произойдет после деления. Однако 33.33 ... не могут быть представлены в точности двоичными числами. Из-за этого вы все еще можете иногда видеть неправильные результаты. Поскольку вы сохраняете результат как целое число, после умножения все равно будет происходить округление, что сделает его более очевидным. Если вы хотите использовать целочисленный тип, вы должны использовать функцию round для результата:

int percent = round((100.0 / combinations) * rightAnswers);

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

float percent = (100.0 / combinations) * rightAnswers;
NSLog(@"Completed %.1f percent",percent); // Display result with 1 decimal place

Наконец, поскольку математика с плавающей запятой по-прежнему вызывает округление для чисел, которые не могут быть представлены в двоичном виде, я бы предложил умножить на rightAnswers перед делением на combinations. Это увеличит шансы на то, что результат представим. Например, 100/3=33.33 ... не представимо и будет округлено. Если вы сначала умножите на 3, вы получите 300/3=100, которое представимо и не будет округлено.

3 голосов
/ 12 июля 2011

Целые числа - это целые числа. Они не могут представлять произвольное действительное число, такое как 1/3. Даже числа с плавающей точкой, которые могут представлять действительные числа, не будут иметь достаточной точности для представления бесконечно повторяющейся десятичной дроби, например 100/3. Вам нужно либо использовать библиотеку произвольной точности, либо использовать библиотеку, включающую рациональные числа в качестве типа данных, или просто хранить столько точности, сколько вам нужно, и округлять оттуда (например, сделать целочисленную единицу измерения сотой доли процента). вместо одного процентного пункта).

2 голосов
/ 12 июля 2011

Возможно, вы захотите внедрить какое-то округление, потому что 33,333 .... * 3 = 99,999999%.3/10 - это бесконечное десятичное число, поэтому вам нужно какое-то округление (возможно, в третьем десятичном знаке), чтобы получить правильный ответ.Я бы сказал, if (num*1000 % 10 >= 5) num += .01 или что-то в этих строках умножить на 100 ходов в десятичном виде 3 раза, а затем мод возвращает 3-ю цифру (может быть ноль).Вы также можете захотеть округлить в конце только после того, как вы сложите все, чтобы избежать ошибок.РЕДАКТИРОВАТЬ: не понимал, что вы использовали целые числа в конце, сбило меня с толку, вы можете использовать двойные или с плавающей точкой (числа с плавающей точкой немного неточны после 2 или 3 цифр, что в порядке с тем, что вы хотите).

0 голосов
/ 12 июля 2011

100/3 - 33. Целочисленная математика здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...