「ほどほどの大きさの整数を扱える,足し算,引き算,掛算,累乗ができる。ただし,挿入演算子を使うのではない」という仕様の電卓プログラム
digits = 100
carry = function(res) {
len = length(res)
cry = 0
for (i in 1:len) {
t = res[i] + cry
res[i] =t %% 10
cry = t %/% 10
}
if (cry) res[len+1] = cry
res
}
add = function(a, b) {
if (length(a) == 1 && class(a) != "LongInt") a = as.LongInt(a)
if (length(b) == 1 && class(b) != "LongInt") b = as.LongInt(b)
if (a[digits] == 9) a = -compliment(a)
if (b[digits] == 9) b = -compliment(b)
res = carry(a+b)[1:digits]
class(res) = "LongInt"
res
}
sub = function(a, b) add(a, -b)
compliment = function(a) {
add(9-a, c(1, rep(0, digits-1)))[1:digits]
}
operand = function(a) {
if (length(a) == 1 && class(a) != "LongInt") a = as.LongInt(a)
sign = 1
if (a[digits] == 9) {
a = compliment(a)
sign = -1
}
return(list(sign= sign, operand=cutZero(a)))
}
mult = function(a, b) {
a0 = operand(a)
a = a0$operand
b0 = operand(b)
b = b0$operand
len.a = length(a)
len.b = length(b)
res = integer(len.a+len.b)
for (j in 1:len.b) {
for (i in 1:len.a) {
res[i+j-1] = res[i+j-1] + a[i]*b[j]
}
}
res = fillZero(carry(res))
if (length(res) > digits) {
stop("Overflow")
} else if (a0$sign * b0$sign == -1) {
res = compliment(res)
}
class(res) = "LongInt"
res
}
cutZero = function(a) {
a = rev(a)
res = rev(a[cumsum(a) > 0])
res
}
fillZero = function(a) {
res = a
len = length(a)
if (digits > len) res = c(res, rep(0, digits-len))
res
}
as.LongInt = function(a) {
res = rev(unlist(strsplit(as.character(a), "")))
len = length(res)
if (res[len] == "-") {
res = compliment(fillZero(as.integer(res[-len])))
} else {
res = as.integer(res)
}
res = fillZero(res)
class(res) = c("LongInt", "integer")
res
}
print.LongInt = function(a) {
if (all(a == 0)) {
a = 0
} else {
Sign = ""
if (a[digits] == 9) {
a = compliment(a)
Sign = "-"
}
a = paste0(Sign, paste(rev(cutZero(a)), collapse=""))
}
cat(a, "\n", sep="")
return(a)
}
power = function(a, n) {
if (length(a) == 1 && class(a) != "LongInt") a = as.LongInt(a)
result = as.LongInt(1)
for (i in 1:n) {
result = mult(result, a)
}
result
}
square = function(a) power(a, 2)
cubic = function(a) power(a, 3)
###
> add(-13, 3)
-10
> mult(123, 5)
615
> sub(add(square(3), square(4)), square(5))
0
>
> a = as.LongInt(5999856)
> b = as.LongInt("99992800") # 大きな数値は文字型で与えると安心
> c = as.LongInt("100000000")
> sub(add(cubic(a), cubic(b)), cubic(c))
-2985984
>
> # 階乗
> a = as.LongInt(1) # これは必須
> for (i in 1:60) a = mult(a,i)
> a
8320987112741390144276341183223364380754172606361245952449277696409600000000000000
> library(gmp)
> factorialZ(60)
Big Integer ('bigz') :
[1] 8320987112741390144276341183223364380754172606361245952449277696409600000000000000
>
> # 2 のべき乗
> power(2, 300)
2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376
> as.bigz(2)^300
Big Integer ('bigz') :
[1] 2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376
>
> # フィボナッチ数列
> n = 400
> a = as.LongInt(1)
> b = as.LongInt(1)
> for (i in 3:n) {
+ c = add(a, b)
+ a = b
+ b = c
+ }
> c
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
> fibnum(n)
Big Integer ('bigz') :
[1] 176023680645013966468226945392411250770384383304492191886725992896575345044216019675