@@ -241,7 +241,7 @@ extension Decimal {
241241extension Decimal : Hashable , Comparable {
242242 internal var doubleValue : Double {
243243 var d = 0.0
244- if _length == 0 && _isNegative == 0 {
244+ if _length == 0 && _isNegative == 1 {
245245 return Double . nan
246246 }
247247 for i in 0 ..< 8 {
@@ -644,7 +644,7 @@ fileprivate extension UInt16 {
644644 }
645645}
646646
647- fileprivate func decimalCompare < T: VariableLengthNumber > (
647+ fileprivate func mantissaCompare < T: VariableLengthNumber > (
648648 _ left: T ,
649649 _ right: T ) -> ComparisonResult {
650650
@@ -655,7 +655,7 @@ fileprivate func decimalCompare<T:VariableLengthNumber>(
655655 return . orderedAscending
656656 }
657657 let length = left. _length // == right._length
658- for i in 0 ..< length {
658+ for i in ( 0 ..< length) . reversed ( ) {
659659 let comparison = left [ i] . compareTo ( right [ i] )
660660 if comparison != . orderedSame {
661661 return comparison
@@ -1131,7 +1131,7 @@ public func NSDecimalAdd(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand:
11311131 }
11321132 result. pointee. _length = length
11331133 } else { // not the same sign
1134- let comparison = decimalCompare ( a, b)
1134+ let comparison = mantissaCompare ( a, b)
11351135
11361136 switch comparison {
11371137 case . orderedSame:
@@ -1417,6 +1417,17 @@ public func NSDecimalString(_ dcm: UnsafePointer<Decimal>, _ locale: AnyObject?)
14171417 return dcm. pointee. description
14181418}
14191419
1420+ private func multiplyBy10( _ dcm: inout Decimal , andAdd extra: Int ) -> NSDecimalNumber . CalculationError {
1421+ let backup = dcm
1422+
1423+ if multiplyByShort ( & dcm, 10 ) == . noError && addShort ( & dcm, UInt16 ( extra) ) == . noError {
1424+ return . noError
1425+ } else {
1426+ dcm = backup // restore the old values
1427+ return . overflow // this is the only possible error
1428+ }
1429+ }
1430+
14201431fileprivate protocol VariableLengthNumber {
14211432 var _length : UInt32 { get set }
14221433 init ( )
@@ -1728,7 +1739,7 @@ extension Decimal {
17281739 var selfNormal = self
17291740 var otherNormal = other
17301741 _ = NSDecimalNormalize ( & selfNormal, & otherNormal, . down)
1731- let comparison = decimalCompare ( selfNormal, otherNormal)
1742+ let comparison = mantissaCompare ( selfNormal, otherNormal)
17321743 if selfNormal. _isNegative == 1 {
17331744 if comparison == . orderedDescending {
17341745 return . orderedAscending
@@ -1903,3 +1914,161 @@ fileprivate let pow10 = [
19031914/*^38*/ Decimal ( length: 8 , mantissa: ( 0x0000 , 0x0000 , 0x2240 , 0x098a , 0xc47a , 0x5a86 , 0x4ca8 , 0x4b3b ) )
19041915/*^39 is on 9 shorts. */
19051916]
1917+
1918+ // Copied from NSScanner.swift
1919+ private func decimalSep( _ locale: Locale ? ) -> String {
1920+ if let loc = locale {
1921+ if let sep = loc. _bridgeToObjectiveC ( ) . object ( forKey: . decimalSeparator) as? NSString {
1922+ return sep. _swiftObject
1923+ }
1924+ return " . "
1925+ } else {
1926+ return decimalSep ( Locale . current)
1927+ }
1928+ }
1929+
1930+ // Copied from NSScanner.swift
1931+ private func isADigit( _ ch: unichar ) -> Bool {
1932+ struct Local {
1933+ static let set = CharacterSet . decimalDigits
1934+ }
1935+ return Local . set. contains ( UnicodeScalar ( ch) !)
1936+ }
1937+
1938+ // Copied from NSScanner.swift
1939+ private func numericValue( _ ch: unichar ) -> Int {
1940+ if ( ch >= unichar ( unicodeScalarLiteral: " 0 " ) && ch <= unichar ( unicodeScalarLiteral: " 9 " ) ) {
1941+ return Int ( ch) - Int( unichar ( unicodeScalarLiteral: " 0 " ) )
1942+ } else {
1943+ return __CFCharDigitValue ( UniChar ( ch) )
1944+ }
1945+ }
1946+
1947+ // Could be silently inexact for float and double.
1948+ extension Scanner {
1949+
1950+ public func scanDecimal( _ dcm: inout Decimal ) -> Bool {
1951+ if let result = scanDecimal ( ) {
1952+ dcm = result
1953+ return true
1954+ } else {
1955+ return false
1956+ }
1957+
1958+ }
1959+ public func scanDecimal( ) -> Decimal ? {
1960+
1961+ var result = Decimal ( )
1962+
1963+ let string = self . _scanString
1964+ let length = string. length
1965+ var buf = _NSStringBuffer ( string: string, start: self . _scanLocation, end: length)
1966+
1967+ let ds_chars = decimalSep ( locale) . utf16
1968+ let ds = ds_chars [ ds_chars. startIndex]
1969+ buf. skip ( _skipSet)
1970+ var neg = false
1971+
1972+ if buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " + " ) {
1973+ neg = buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " )
1974+ buf. advance ( )
1975+ buf. skip ( _skipSet)
1976+ }
1977+ guard isADigit ( buf. currentCharacter) else {
1978+ return nil
1979+ }
1980+
1981+ var tooBig = false
1982+
1983+ // build the mantissa
1984+ repeat {
1985+ let numeral = numericValue ( buf. currentCharacter)
1986+ if numeral == - 1 {
1987+ break
1988+ }
1989+
1990+ if tooBig || multiplyBy10 ( & result, andAdd: numeral) != . noError {
1991+ tooBig = true
1992+ if result. _exponent == Int32 ( Int8 . max) {
1993+ repeat {
1994+ buf. advance ( )
1995+ } while isADigit ( buf. currentCharacter)
1996+ return Decimal . nan
1997+ }
1998+ result. _exponent += 1
1999+ }
2000+ buf. advance ( )
2001+ } while isADigit ( buf. currentCharacter)
2002+
2003+ // get the decimal point
2004+ if buf. currentCharacter == ds {
2005+ buf. advance ( )
2006+ // continue to build the mantissa
2007+ repeat {
2008+ let numeral = numericValue ( buf. currentCharacter)
2009+ if numeral == - 1 {
2010+ break
2011+ }
2012+ if tooBig || multiplyBy10 ( & result, andAdd: numeral) != . noError {
2013+ tooBig = true
2014+ } else {
2015+ if result. _exponent == Int32 ( Int8 . min) {
2016+ repeat {
2017+ buf. advance ( )
2018+ } while isADigit ( buf. currentCharacter)
2019+ return Decimal . nan
2020+ }
2021+ result. _exponent -= 1
2022+ }
2023+ buf. advance ( )
2024+ } while isADigit ( buf. currentCharacter)
2025+ }
2026+
2027+ if buf. currentCharacter == unichar ( unicodeScalarLiteral: " e " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " E " ) {
2028+ var exponentIsNegative = false
2029+ var exponent : Int32 = 0
2030+
2031+ buf. advance ( )
2032+ if buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " ) {
2033+ exponentIsNegative = true
2034+ buf. advance ( )
2035+ } else if buf. currentCharacter == unichar ( unicodeScalarLiteral: " + " ) {
2036+ buf. advance ( )
2037+ }
2038+
2039+ repeat {
2040+ let numeral = numericValue ( buf. currentCharacter)
2041+ if numeral == - 1 {
2042+ break
2043+ }
2044+ exponent = 10 * exponent + numeral
2045+ guard exponent <= 2 * Int32( Int8 . max) else {
2046+ return Decimal . nan
2047+ }
2048+
2049+ buf. advance ( )
2050+ } while isADigit ( buf. currentCharacter)
2051+
2052+ if exponentIsNegative {
2053+ exponent = - exponent
2054+ }
2055+ exponent += result. _exponent
2056+ guard exponent >= Int32 ( Int8 . min) && exponent <= Int32 ( Int8 . max) else {
2057+ return Decimal . nan
2058+ }
2059+ result. _exponent = exponent
2060+ }
2061+
2062+ result. isNegative = neg
2063+
2064+ // if we get to this point, and have NaN, then the input string was probably "-0"
2065+ // or some variation on that, and normalize that to zero.
2066+ if result. isNaN {
2067+ result = Decimal ( 0 )
2068+ }
2069+
2070+ result. compact ( )
2071+ self . _scanLocation = buf. location
2072+ return result
2073+ }
2074+ }
0 commit comments