2010-10-20 10 views
20

estoy teniendo el momento más difícil de averiguar algo que parece que debería ser muy simple. Necesito redondear con precisión un NSDecimalNumber a un número particular de decimales (determinado en tiempo de ejecución). Por lo que puedo ver, tengo dos opciones, ninguna de las cuales me gusta.Redondeo NSDecimalNumber

  1. Convertir a un flotador, y el uso de C funciones de redondeo: no me gusta esto porque los asuntos de exactitud en este caso. Los flotantes no siempre pueden representar números decimales con precisión, y esto podría causar problemas.
  2. Convierta a una cadena usando NSNumberFormatter y luego convierta de nuevo: No me gusta porque me parece feo e ineficiente.

¿Hay otra manera de que me he perdido? Tiene tiene que haber una manera fácil de hacer el redondeo de NSDecimalNumbers, pero me parece que no puede averiguar por la vida de mí lo que es.

Respuesta

32

sólo tiene que llamar decimalNumberByRoundingAccordingToBehavior: con el NSDecimalNumberBehaviors protocolo deseado. Consulte la referencia NSDecimalNumberBehaviors en el dev docs.

Actualización: Ver http://www.cimgf.com/2008/04/23/cocoa-tutorial-dont-be-lazy-with-nsdecimalnumber-like-me/

+0

Ese es el billete! ¡Gracias! –

+0

Excelente enlace también :-) –

+0

RTFM no fue la respuesta. La respuesta fue "Simplemente llame a decimalNumberByRoundingAccordingToBehavior: con el protocolo NSDecimalNumberBehaviors deseado". Se hizo referencia a los documentos de desarrollo para proporcionar la enumeración de varios protocolos en lugar de copiarlos aquí. – CuriousRabbit

17

Para aquellos que prefieren código de ejemplo ...

Para redondear a 2 decimales (12.345,68):

NSDecimalNumber *originalNumber = [NSDecimalNumber decimalNumberWithString:@"12345.6789"]; 
NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain 
                          scale:2 
                       raiseOnExactness:NO 
                       raiseOnOverflow:NO 
                       raiseOnUnderflow:NO 
                      raiseOnDivideByZero:NO]; 

NSDecimalNumber *roundedNumber = [originalNumber decimalNumberByRoundingAccordingToBehavior:behavior]; 

Para redondear al más cercano mil (12.000):

NSDecimalNumber *originalNumber = [NSDecimalNumber decimalNumberWithString:@"12345.6789"]; 
NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain 
                          scale:-3 
                       raiseOnExactness:NO 
                       raiseOnOverflow:NO 
                       raiseOnUnderflow:NO 
                      raiseOnDivideByZero:NO]; 

NSDecimalNumber *roundedNumber = [originalNumber decimalNumberByRoundingAccordingToBehavior:behavior]; 
3

Lo tengo trabajando usando el siguiente código en Swift 3.

let amount = NSDecimalNumber(string: "123.456789") 
let handler = NSDecimalNumberHandler(roundingMode: .plain, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false) 
let roundedAmount = amount.rounding(accordingToBehavior: handler) 

Tenga en cuenta el parámetro de escala, que se utiliza para definir los lugares decimales que necesita. Esbozado aquí: https://developer.apple.com/reference/foundation/nsdecimalnumberhandler/1578295-decimalnumberhandlerwithrounding

0

estoy usando esta solución:

import Foundation 

extension NSDecimalNumber { 
    public func round(_ decimals:Int) -> NSDecimalNumber { 
     return self.rounding(accordingToBehavior: 
      NSDecimalNumberHandler(roundingMode: .plain, 
            scale: Int16(decimals), 
            raiseOnExactness: false, 
            raiseOnOverflow: false, 
            raiseOnUnderflow: false, 
            raiseOnDivideByZero: false)) 
    } 
} 

let amount = NSDecimalNumber(string: "123.456") 

amount.round(2) --> 123.46 
amount.round(1) --> 123.5 
amount.round(0) --> 123 
amount.round(-1) --> 120 
amount.round(-2) --> 100