Parcourir la source

Fixed signup issue for BigNum, for + and - operators.

Damian Kołakowski il y a 9 ans
Parent
commit
21e40be64e

+ 70 - 5
Sources/TLS/BigNum.swift

@@ -7,7 +7,7 @@
 
 import Foundation
 
-public struct BigNum: Equatable, Comparable {
+public struct BigNum: Equatable, Comparable, CustomStringConvertible {
     
     //
     // Big Integer
@@ -31,7 +31,21 @@ public struct BigNum: Equatable, Comparable {
     }
     
     public init(_ text: String) {
-        self.signum = text.unicodeScalars.isEmpty ? 0 : 1
+        
+        if text.unicodeScalars.isEmpty {
+            self.signum = 0
+            self.digits = [0]
+            return
+        }
+        
+        if text.unicodeScalars.count == 1 && text.unicodeScalars[text.unicodeScalars.startIndex].value == 48 {
+            self.signum = 0
+            self.digits = [0]
+            return
+        }
+        
+        self.signum = 1
+        
         for c in text.unicodeScalars.reversed() {
             switch c.value {
             case 48...57:
@@ -42,6 +56,10 @@ public struct BigNum: Equatable, Comparable {
             }
         }
     }
+    
+    public var description: String {
+        return (self.signum < 0 ? "-" : "") + self.digits.reversed().reduce("") { $0 + String($1) }
+    }
 }
 
 infix operator == { precedence 130 }
@@ -56,6 +74,27 @@ public func != (_ left: BigNum, right: BigNum) -> Bool {
 
 infix operator + { associativity left precedence 140 }
 public func + (_ left: BigNum, _ right: BigNum) -> BigNum {
+    
+    if right.signum == 0 {
+        return left
+    }
+    
+    if left.signum == 0 {
+        return right
+    }
+    
+    if left.signum < 0 && right.signum < 0 {
+        return BigNum((BigNum(left.digits, 1) + BigNum(right.digits, 1)).digits, -1)
+    }
+    
+    if left.signum > 0 && right.signum < 0 {
+        return (left - BigNum(right.digits, 1))
+    }
+    
+    if left.signum < 0 && right.signum > 0 {
+        return BigNum((right - BigNum(left.digits, 1)).digits, -1)
+    }
+    
     var result = [UInt8]()
     var carry: UInt8 = 0
     for i in 0..<max(left.digits.count, right.digits.count) {
@@ -72,14 +111,38 @@ public func + (_ left: BigNum, _ right: BigNum) -> BigNum {
     if carry != 0 {
         result.append(carry)
     }
-    return BigNum(result, 1)
+    
+    while let last = result.last, last == 0 { result.removeLast() }
+    
+    return result.isEmpty ? BigNum(result, 0) : BigNum(result, 1)
 }
 
 infix operator - { associativity left precedence 140 }
 public func - (_ left: BigNum, _ right: BigNum) -> BigNum {
+    
+    if right.signum == 0 {
+        return left
+    }
+    
+    if left.signum == 0 {
+        return BigNum(right.digits, right.signum * (-1))
+    }
+    
+    if left == right {
+        return BigNum([0], 0)
+    }
+    
+    if right > left {
+        return BigNum((right - left).digits, -1)
+    }
+    
+    if left.signum < 0 && right.signum > 0 {
+        return BigNum((BigNum(left.digits, 1) + right).digits, -1)
+    }
+    
     var result = [UInt8]()
     var carry: Int = 0
-    for i in 0..<max(left.digits.count, right.digits.count) {
+    for i in 0..<max(right.digits.count, left.digits.count) {
         let sub = (Int((i < left.digits.count) ? left.digits[i] : 0) -
             Int((i < right.digits.count) ? right.digits[i] : 0)) + carry
         if sub < 0 {
@@ -90,8 +153,10 @@ public func - (_ left: BigNum, _ right: BigNum) -> BigNum {
             result.append(UInt8(sub))
         }
     }
+    
     while let last = result.last, last == 0 { result.removeLast() }
-    return BigNum(result, 1)
+    
+    return result.isEmpty ? BigNum(result, 0) : BigNum(result, 1)
 }
 
 infix operator * { associativity left precedence 150 }

+ 6 - 0
XCode/Swifter.xcodeproj/project.pbxproj

@@ -13,6 +13,8 @@
 		7C00AABE1D5D374700EDA547 /* HEX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AABD1D5D374700EDA547 /* HEX.swift */; };
 		7C00AABF1D5D374700EDA547 /* HEX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AABD1D5D374700EDA547 /* HEX.swift */; };
 		7C00AAC01D5D374700EDA547 /* HEX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AABD1D5D374700EDA547 /* HEX.swift */; };
+		7C00AAC21D5D995900EDA547 /* SwifterTestsBigNum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AAC11D5D995900EDA547 /* SwifterTestsBigNum.swift */; };
+		7C00AAC31D5D995900EDA547 /* SwifterTestsBigNum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C00AAC11D5D995900EDA547 /* SwifterTestsBigNum.swift */; };
 		7C13B57C1C7B069500556443 /* SwifterTestsSQLite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C13B57B1C7B069500556443 /* SwifterTestsSQLite.swift */; };
 		7C13B57D1C7B069500556443 /* SwifterTestsSQLite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C13B57B1C7B069500556443 /* SwifterTestsSQLite.swift */; };
 		7C3195FB1CC2C68F00DF5406 /* sqlite.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C3195E31CC2C68F00DF5406 /* sqlite.h */; };
@@ -224,6 +226,7 @@
 		7AE893FF1C0512C400A29F63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		7AE8940C1C05151100A29F63 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
 		7C00AABD1D5D374700EDA547 /* HEX.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HEX.swift; sourceTree = "<group>"; };
+		7C00AAC11D5D995900EDA547 /* SwifterTestsBigNum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwifterTestsBigNum.swift; sourceTree = "<group>"; };
 		7C13B57B1C7B069500556443 /* SwifterTestsSQLite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwifterTestsSQLite.swift; sourceTree = "<group>"; };
 		7C2C85901D50D83D00B32145 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
 		7C3195E31CC2C68F00DF5406 /* sqlite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite.h; sourceTree = "<group>"; };
@@ -528,6 +531,7 @@
 				7C5F78F51D54D21600C514AA /* SwifterTestsRC4.swift */,
 				7C5F78EE1D54BB5600C514AA /* SwifterTestsAES128.swift */,
 				7CE0B9EE1D5BBAAD0070D292 /* SwifterTestsHMAC.swift */,
+				7C00AAC11D5D995900EDA547 /* SwifterTestsBigNum.swift */,
 				7C5F79031D55F44500C514AA /* SwifterTestsRSA.swift */,
 				7CCD875D1C66099B0068099B /* SwifteriOSTests */,
 			);
@@ -1030,6 +1034,7 @@
 				7CCD87701C660B250068099B /* SwifterTestsHttpParser.swift in Sources */,
 				7C5F79041D55F44500C514AA /* SwifterTestsRSA.swift in Sources */,
 				7C6B57EB1CA6C3AA0042655C /* SwifterTestsHttpRouter.swift in Sources */,
+				7C00AAC21D5D995900EDA547 /* SwifterTestsBigNum.swift in Sources */,
 				7C5915221C92A99300D884BC /* SwifterTestsReflection.swift in Sources */,
 				7C13B57C1C7B069500556443 /* SwifterTestsSQLite.swift in Sources */,
 				7CB923D01D510D6400899E2A /* SwifterTestsJSON.swift in Sources */,
@@ -1048,6 +1053,7 @@
 				7CCD87841C660ED60068099B /* SwifterTestsHttpParser.swift in Sources */,
 				7C5F79051D55F44500C514AA /* SwifterTestsRSA.swift in Sources */,
 				7C6B57EC1CA6C3AA0042655C /* SwifterTestsHttpRouter.swift in Sources */,
+				7C00AAC31D5D995900EDA547 /* SwifterTestsBigNum.swift in Sources */,
 				7C5915231C92A99300D884BC /* SwifterTestsReflection.swift in Sources */,
 				7C13B57D1C7B069500556443 /* SwifterTestsSQLite.swift in Sources */,
 				7CB923D11D510D6400899E2A /* SwifterTestsJSON.swift in Sources */,

+ 30 - 0
XCode/SwifterTestsCommon/SwifterTestsBigNum.swift

@@ -0,0 +1,30 @@
+//
+//  SwifterTestsBigNum.swift
+//  Swifter
+//
+//  Copyright © 2016 Damian Kołakowski. All rights reserved.
+//
+
+import XCTest
+import Swifter
+
+class SwifterTestsBigNum: XCTestCase {
+    
+    func testAdd() {
+        
+        XCTAssertEqual((BigNum("0") + BigNum("0")).description, "0")
+        XCTAssertEqual((BigNum("1") + BigNum("1")).description, "2")
+        
+        for i in 0...1000 {
+            XCTAssertEqual((BigNum("\(i)") + BigNum("\(2*i)")).description, "\(3*i)")
+        }
+        
+        XCTAssertEqual((BigNum("1") + BigNum("-1")).description, "0")
+        XCTAssertEqual((BigNum("-123") + BigNum("-100")).description, "-223")
+        
+        XCTAssertEqual((BigNum("1212409125082591823512599999923413499") +
+            BigNum("14028715021850212323919319")).description,
+                       "1212409125096620538534450212247332818")
+    }
+
+}