Valor do seno 180 está saindo como 1.22465e-16

Eu quero implementar uma calculadora Sine e Cosine no ios4:

if([operation isEqual:@"sin"]){ operand = (operand*M_PI/180.0); operand=sin(operand); } 

O código me dá resposta correta para valores de 0 a 90.

Quando dou o valor de 180, recebo 1.22465e-16 como resposta. Eu espero zero.

De onde vem essa pequena diferença?

Isso é causado pela incapacidade de um sistema numérico binário representar exatamente PI.

Uma solução possível seria usar a simetria do pecado:

 sindeg(x) = sindeg(180 - x) 

(ou alternativamente):

 sin(x) = sin(M_PI - x) 

Transformar o ângulo no intervalo (-pi / 2: pi / 2) reduz o erro da aproximação.

Basicamente:

 if([operation isEqual:@"sin"]){ operand = fmod(operand, 360); if (operand > 270) operand -= 360; else if (operand > 90) operand = 180 - operand; operand=sin(operand*M_PI/180.0); } 

Só para ficar claro, seu programa está dando a resposta correta . Isto é, está fazendo exatamente o que você disse para fazer no seu código.

180*M_PI é corretamente arredondado (por IEEE-754) e fornece o valor:

 565.4866776461627750904881395399570465087890625 

dividindo isso por 180 também é corretamente arredondado, e dá o resultado:

 3.141592653589793115997963468544185161590576171875 

que não é exatamente o valor matemático de π. De fato, é:

 π - 0.0000000000000001224646799147... 

O termo de primeira ordem da série de Taylor para o sin(x) torno de π é (π-x), então sin(π - x) é, para x pequeno, quase exatamente -x . Na verdade, o resultado que você está obtendo é o resultado corretamente arredondado . A biblioteca não poderia fornecer uma resposta mais precisa.

Como Ben Voigt sugeriu, se isso for realmente um problema para você, você pode contornar isso reduzindo o argumento no intervalo [-90, 90) antes de converter de graus para radianos. Uma sugestão ainda melhor é que os njuffa usem uma function sinpi que faça esse trabalho para você. iOS não tem essa function, mas tem vvsinpi , que implementa sin (π * x) para vetores, e pode ser feito para fazer o que você quer:

 double result; int vectorLength = 1; vvsinpi(&result, &operand, &vectorLength); 

Por favor, envie um bug solicitando que sinpi seja adicionado à biblioteca de matemática como uma extensão.

Você pode querer verificar se a biblioteca de matemática nesta plataforma oferece a function sinpi () como uma extensão para as funções de biblioteca matemática padrão C / C ++. Isso evitaria multiplicação explícita com o valor aproximado de pi (ie M_PI) e lhe daria maior precisão.

 operand = sinpi (operand / 180.0) 

Você depende do tipo de dados de ponto flutuante em seu processador. Com (muito considerável) mais esforço, você pode implementar um tipo de dados de precisão arbitrária. Olhe para MPFR http://www.mpfr.org/sample.html, ele contém uma definição para funções (como sin) que fornecerá um número maior de dígitos.