2016-07-08 7 views
0

は、私が最も近いダニに株式、指数先物の価格を丸めるする必要があります。最初のステップは、価格がティックの倍数であるかどうかを調べることです。アップルのドキュメントは言う、「CとObjective-C、また、浮動小数点数上で動作することができスウィフトの剰余演算における剰余演算子とは異なり」。スウィフト剰余演算精度

私が遊び場やコンソールアプリケーションに次のコードを書いて、私はそれを実行した場合、私は結果としてを期待するが、私は余り値が0.00999999999999775に等しい取得:

var stringPrice = "17.66" 
var price = Double(stringPrice) 
var tickSize: Double = 0.01 

let remainder = price! % ticksize 

この17.66このようaTickSizeなどaPriceや0.01などの値を使用した場合の問題は、私の丸め関数を破る:

func roundPriceToNearestTick(Price aPrice: Double, TickSize a TickSize: Double)-> Double{ 
    let remainder = aPrice % aTickSize 
    let shouldRoundUp = remainder >= aTickSize/2 ? true : false 
    let multiple = floor(aPrice/aTickSize) 
    let returnPrice = !shouldRoundUp ? aTickSize*multiple : aTickSize*multiple + aTickSize 
    return returnPrice 
} 

この問題を解決する最良の方法は何ですか?

+3

これはと同じ問題である(http://stackoverflow.com/questions/588004/is-floating-point-math-broken)[小数点演算が壊れて浮いている?] - '17.66'にすることはできませんバイナリ浮動小数点数として正確に表現されています。お金に関するすべての操作のための –

+3

使用 'NSDecimalNumber'、山車とダブルスを避けます。ユーザーに小数の値を提示するために、 'NSNumberFormatter'を使用してください。自分でラウンド値にしないでください、それはあなたが思っているよりはるかに複雑な問題です。 – Sulthan

答えて

0

壊れた浮動小数点演算とお金に関するすべての操作の山車とダブルスを回避する必要性についてのコメントに続いて、私はNSDecimalNumbersを使用して剰余演算を実行するために自分のコードを変更しました。これは精度問題を解決するようです。

var stringPrice = "17.66" 
var tickSizeDouble : Double = 0.01 
var tickSizeDecimalNumber: NSDecimalNumber = 0.01 

func decimalNumberRemainder(Dividend aDividend: NSDecimalNumber, Divisor aDivisor: NSDecimalNumber)->NSDecimalNumber{ 

    let behaviour = NSDecimalNumberHandler(roundingMode: NSRoundingMode.RoundDown, 
                scale: 0, 
             raiseOnExactness: false , 
             raiseOnOverflow: false, 
             raiseOnUnderflow: false, 
            raiseOnDivideByZero: false) 

    let quotient = aDividend.decimalNumberByDividingBy(aDivisor, withBehavior: behaviour) 
    let subtractAmount = quotient.decimalNumberByMultiplyingBy(aDivisor) 
    let remainder = aDividend.decimalNumberBySubtracting(subtractAmount) 
    return remainder 
} 


let doubleRemainder = Double(stringPrice)! % tickSizeDouble 
let decimalRemainder = decimalNumberRemainder(Dividend: NSDecimalNumber(string: stringPrice), Divisor:tickSizeDecimalNumber) 


print("Using Double: \(doubleRemainder)") 
print("Using NSDecimalNumber: \(decimalRemainder)") 
関連する問題