Created
September 10, 2018 11:26
-
-
Save BlueRayi/5bba14d9a27cceecb5764b429a032289 to your computer and use it in GitHub Desktop.
有理数構造体(貧弱)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
prefix operator / | |
public prefix func +(rhs: Rational) -> Rational // これいる? | |
{ | |
return Rational(rhs.pee, rhs.cue) | |
} | |
public prefix func -(rhs: Rational) -> Rational // 反数 | |
{ | |
return Rational(-rhs.pee, rhs.cue) | |
} | |
public prefix func /(rhs: Rational) -> Rational // 逆数 | |
{ | |
if rhs.pee < 0 { | |
return Rational(-rhs.cue, -rhs.pee) | |
} else { | |
return Rational(rhs.cue, rhs.pee) | |
} | |
} | |
public func +(lhs: Rational, rhs: Rational) -> Rational | |
{ | |
return Rational(lhs.pee * rhs.cue + rhs.pee * lhs.cue, lhs.cue * rhs.cue) // 1/0を無限遠点とする実装 | |
} | |
public func -(lhs: Rational, rhs: Rational) -> Rational | |
{ | |
return lhs + (-rhs) | |
} | |
public func *(lhs: Rational, rhs: Rational) -> Rational | |
{ | |
return Rational(lhs.pee * rhs.pee, lhs.cue * rhs.cue) | |
} | |
public func /(lhs: Rational, rhs: Rational) -> Rational | |
{ | |
return lhs * (/rhs) | |
} | |
public func +=(lhs: inout Rational, rhs: Rational) | |
{ | |
lhs = lhs + rhs | |
} | |
public func -=(lhs: inout Rational, rhs: Rational) | |
{ | |
lhs = lhs - rhs | |
} | |
public func *=(lhs: inout Rational, rhs: Rational) | |
{ | |
lhs = lhs * rhs | |
} | |
public func /=(lhs: inout Rational, rhs: Rational) | |
{ | |
lhs = lhs / rhs | |
} | |
public func ==(lhs: Rational, rhs: Rational) -> Bool | |
{ | |
if lhs.isIndeterminate || rhs.isIndeterminate { // 1/0を無限遠点とする実装 | |
return false | |
} else { | |
return lhs.pee * rhs.cue == rhs.pee * lhs.cue | |
} | |
} | |
public func !=(lhs: Rational, rhs: Rational) -> Bool | |
{ | |
return !(lhs == rhs) | |
} | |
public func <(lhs: Rational, rhs: Rational) -> Bool | |
{ | |
if lhs.isIndeterminate || rhs.isIndeterminate { | |
return false | |
} else { | |
if lhs.isInfinite { // 1/0を無限遠点とする実装 | |
if rhs.pee < 0 { | |
return true | |
} else { | |
return false | |
} | |
} else if rhs.isInfinite { // 1/0を無限遠点とする実装 | |
if lhs.pee > 0 { | |
return true | |
} else { | |
return false | |
} | |
} else { | |
return lhs.pee * rhs.cue < rhs.pee * lhs.cue | |
} | |
} | |
} | |
public func <=(lhs: Rational, rhs: Rational) -> Bool | |
{ | |
return lhs == rhs || lhs < rhs | |
} | |
public func >(lhs: Rational, rhs: Rational) -> Bool | |
{ | |
if lhs.isIndeterminate || rhs.isIndeterminate { | |
return false | |
} else { | |
if lhs.isInfinite { // 1/0を無限遠点とする実装 | |
if rhs.pee > 0 { | |
return true | |
} else { | |
return false | |
} | |
} else if rhs.isInfinite { // 1/0を無限遠点とする実装 | |
if lhs.pee < 0 { | |
return true | |
} else { | |
return false | |
} | |
} else { | |
return lhs.pee * rhs.cue > rhs.pee * lhs.cue | |
} | |
} | |
} | |
public func >=(lhs: Rational, rhs: Rational) -> Bool | |
{ | |
return lhs == rhs || lhs > rhs | |
} | |
extension Rational: ExpressibleByIntegerLiteral | |
{ | |
public init(integerLiteral value: IntegerLiteralType) | |
{ | |
self.init(value) | |
} | |
} | |
extension Rational: CustomStringConvertible | |
{ | |
public var description: String { | |
switch self.cue { | |
case 1: | |
return "\(self.pee)" | |
case 0: | |
switch self.pee { // 1/0を無限遠点とする実装 | |
case 1: | |
return "∞" | |
case 0: | |
return "不定形" | |
default: | |
return "メッセージは出ないはずだよ" | |
} | |
default: | |
return Rational.sup(self.pee) + "/" + Rational.sub(self.cue) | |
} | |
} | |
} | |
public struct Rational: Equatable | |
{ | |
fileprivate let pee: Int | |
fileprivate let cue: Int | |
public var numer: Int { return self.pee } | |
public var denom: Int { return self.cue } | |
public var isFinite: Bool { return self.cue != 0 } | |
public var isInfinite: Bool { return self.cue == 0 && self.pee != 0} | |
public var isIndeterminate: Bool { return self.cue == 0 && self.pee == 0 } | |
public init(_ pee: Int, _ cue: Int) | |
{ | |
let xxx = Rational.gcd(pee, cue) | |
if cue == 0 { // 1/0を無限遠点とする実装 | |
self.cue = 0 | |
if pee == 0 { | |
self.pee = 0 | |
} else { | |
self.pee = 1 | |
} | |
} else { | |
if (xxx < 0) == (cue < 0) { | |
self.pee = pee / xxx | |
self.cue = cue / xxx | |
} else { | |
self.pee = -pee / xxx | |
self.cue = -cue / xxx | |
} | |
} | |
} | |
public init(_ pee: Int) | |
{ | |
self.pee = pee | |
self.cue = 1 | |
} | |
fileprivate static func gcd(_ a: Int, _ b: Int) -> Int | |
{ | |
switch b { | |
case 0: | |
return a | |
default: | |
return gcd(b, a % b) | |
} | |
} | |
fileprivate static func sup(_ number: Int) -> String | |
{ | |
return String(number) | |
} | |
fileprivate static func sub(_ number: Int) -> String | |
{ | |
return String(number) | |
} | |
} | |
var foo = Rational(2) | |
print(foo) // 2 | |
foo = Rational(2, 4) | |
print(foo) // 1/2 | |
print("約分も当然できます") | |
foo = 3 | |
print(foo) // 3 | |
print("\(foo)の反数は\(-foo)、逆数は\(/foo)") // 3の反数は-3、逆数は1/3 | |
var bar = Rational(9, 5) | |
print("\(foo) ÷ \(bar) = \(foo / bar)") //3 ÷ 9/5 = 5/3 | |
print("計算結果も約分します") | |
foo = 5 | |
bar = 0 | |
print("ゼロ除算…5/0 = \(foo / bar)、0/0 = \(bar / bar)") // 5/0 = ∞、0/0 = 不定形 | |
print("定番の二進数丸め誤差誤差計算は?") | |
let float = 0.1 | |
let rational = Rational(1, 10) | |
var floatSum: Double = 0 | |
var rationalSum: Rational = 0 | |
for _ in 0 ..< 10 { | |
floatSum += float | |
rationalSum += rational | |
} | |
print("float: \(float) * 10 = 1.0? -> \(floatSum)…しかし\(floatSum == 1.0)") // 1.0…しかしfalse | |
print("rational: \(rational) * 10 = 1? -> \(rationalSum)…当然\(rationalSum == 1)") // 1…当然true | |
print("素晴らしきかな有理数!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment