Pergunta

Como eu comecei a codificação meu primeiro aplicativo que eu usei NSNumber para valores monetários sem pensar duas vezes. Então eu pensei que talvez c tipos foram suficientes para lidar com os meus valores. No entanto, fui aconselhado no fórum iPhone SDK usar NSDecimalNumber, por causa de suas excelentes capacidades de arredondamento.

Não sendo um matemático por temperamento, eu pensei que o mantissa / expoente paradigma pode ser um exagero; ainda, googlin' ??ao redor, percebi que a maioria fala sobre o dinheiro / moeda no cacau foram encaminhados para NSDecimalNumber.

Observe que o aplicativo que eu estou trabalhando vai ser internacionalizado, por isso a opção de contar o montante em centavos não é realmente viável, para a estrutura monetária depende muito do local utilizado.

Estou 90% certo de que eu preciso para ir com NSDecimalNumber, mas desde que eu encontrei nenhuma resposta inequívoca na web (algo como: "se você lidar com dinheiro, usar NSDecimalNumber!") Eu pensei que eu ia perguntar aqui. Talvez a resposta é óbvia para a maioria, mas eu quero ter certeza antes de iniciar um enorme re-factoring do meu aplicativo.

Convença-me:)

Foi útil?

Solução

Marcus Zarra tem uma posição muito clara sobre isso: 'Se você está lidando com a moeda em tudo, então você deve estar usando NSDecimalNumber.' Seu artigo inspirou-me a olhar para NSDecimalNumber, e eu fiquei muito impressionado com ele. IEEE erros de ponto flutuante quando se lida com base-10 de matemática foram me irritar por um tempo (1 * (0,5-0,4 - 0,1) = -,00000000000000002776) e NSDecimalNumber acaba com eles

.

NSDecimalNumber não basta adicionar mais alguns dígitos do binário ponto flutuante de precisão, ele realmente faz base-10 de matemática. Isso se livrar dos erros como o mostrado no exemplo acima.

Agora, eu estou escrevendo um aplicativo de matemática simbólica, por isso o meu desejo de precisão dígitos 30+ decimal e não estranhos erros de ponto flutuante pode ser uma exceção, mas acho que vale a pena olhar. As operações são um pouco mais complicado do que uma simples matemática var = 1 + 2 estilo, mas eles ainda são gerenciáveis. Se você está preocupado sobre a alocação de todos os tipos de casos durante as suas operações matemáticas, NSDecimal é o equivalente C struct de NSDecimalNumber e há funções C para fazer exatamente as mesmas operações matemáticas com ele. Na minha experiência, estes são muito rápido para todos, mas as aplicações exigentes maioria (3,344,593 adições / s, 254,017 divisões / s em um MacBook Air, 281,555 adições / s, 12.027 divisões / s em um iPhone).

Como um bônus adicional, descriptionWithLocale de NSDecimalNumber: método fornece uma string com uma versão localizada do número, incluindo o separador decimal correto. O mesmo se passa em sentido inverso para a sua initWithString: local:. Método

Outras dicas

Sim. Você tem que usar

NSDecimalNumber e

não duplo ou flutuador quando você lida com moeda no iOS.

Por que é isso ??

Porque nós não queremos fazer as coisas como $ 9,9999999998 em vez de $ 10

Como isso acontece ??

flutua e duplas são aproximações. Eles sempre vem com um erro de arredondamento. Os computadores formato usar para armazenar decimais causa esse erro de alavancas arredondadas. Se você precisar de mais detalhes, leia

http://floating-point-gui.de/

De acordo com docs maçã,

NSDecimalNumber é uma subclasse imutável de NSNumber, fornece um invólucro orientada a objetos para fazer base 10 aritmética. Um exemplo pode representar qualquer número que pode ser expresso como mantissa x 10 ^ expoente onde mantissa é um número inteiro decimal até 38 dígitos, e expoente é um número inteiro de -128 através 127.wrapper para fazer base 10 aritmética.

Assim NSDecimalNumber é recommonded de acordo com a moeda.

(Adaptado de meu comentário sobre a outra resposta.)

Sim, você deve. Um integrante do número de moedas de um centavo só funciona enquanto você não precisa representar, digamos, meio centavo. Se isso acontecer, você pode alterá-lo para contar meias-centavos, mas que se você precisa então de representar um quarto de centavo, ou um oitavo de um centavo?

A única solução adequada é NSDecimalNumber (ou algo parecido), que adia o problema a 10 ^ -128 ¢ (ou seja,
0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000001 ¢).

(Outra forma seria arbitrária de precisão aritmética, mas que requer uma biblioteca separada, como o GNU MP Bignum biblioteca . GMP está sob a LGPL. Eu nunca usei essa biblioteca e não sei exatamente como ele funciona, então eu não poderia dizer o quão bem ele iria trabalhar para você.)

[Edit: Aparentemente, pelo menos uma pessoa-Brad Larson-pensa que eu estou falando de binário em algum lugar de ponto flutuante nesta resposta. Eu não sou.]

A melhor pergunta é, quando você deve não uso NSDecimalNumber para lidar com dinheiro. A resposta curta a essa pergunta é, quando você não pode tolerar a sobrecarga de NSDecimalNumber desempenho e você não se preocupam com erros de arredondamento pequenas porque você nunca está lidando com mais do que alguns dígitos de precisão. A resposta ainda mais curto é, você deve sempre usar NSDecimalNumber quando se lida com dinheiro.

Eu achei conveniente usar um inteiro para representar o número de centavos e depois dividir por 100 para apresentação. Evita toda a questão.

VISA, MasterCard e outros estão usando valores inteiros ao passar valores. É até remetente e receptor para amouts analisar correctamente de acordo com o expoente da moeda (dividir ou multiplicar por 10 ^ num, onde num - é um expoente da moeda). Note-se que diferentes moedas têm diferentes expoentes. Geralmente é 2 (daí nós dividir e multiplicar por 100), mas algumas moedas têm expoente = 0 (VND, etc), ou = 3.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top