エレファント・ビジュアライザー調査記録

ビジュアルプログラミングで数式の変形を表すことを考えていくブロクです。

関数プログラミングと無限論理多項式(7)

Python の例(2)

F# のコードから移植したので少し間違っているところがありましたので修正します。そのほか移植したときにわかりやすいようにコンストラクターを変更しました。また、メソッド名も少し変更しました。

Python のコード

def Align0(xs, leng, z):
    return xs + [z] * (leng - len(xs))

def ZipWith0(z, f, xs, ys):
    xsx = Align0(xs, len(ys), z)
    ysx = Align0(ys, len(xs), z)
    return list(map(lambda cpl: f(cpl[0], cpl[1]), list(zip(xsx, ysx))))

def Iterate(next, init):
    cur = init
    while True:
        yield cur
        cur = next(cur)

def Take(count, seq):
    c = count
    for e in seq:
        if c == 0:
            break
        c -= 1
        yield e

def CarryStep(carry_and_dec, x):
    carry, dec = carry_and_dec
    newdec = LongDecimal([(x + carry) % 10] + dec.decimals)
    return  ((x + carry) // 10, newdec)

from functools import reduce

class LongDecimal:
    #def __init__(self, ns, e):
    #    self.decimals = [0] * e + ns
    def __init__(self, ns):
        self.decimals = ns
    def Decimalize(self, c, leave):
        carry, dec = reduce(CarryStep, self.decimals[::-1], (c, LongDecimal([])))
        if leave and carry != 0:
            return dec.Sum1(carry * 10)
        else:
            return dec
    def Shift(self, e):
        return LongDecimal([0] * e + self.decimals)
    def CollectShiftMult(self, y):
        e = 0
        for xd in self.decimals:
                yield y.Product1(xd).Shift(e)
                e += 1
    def Sum1(self, y):
        return LongDecimal([self.decimals[0] + y] + self.decimals[1:])
    def Sum(self, y):
        return LongDecimal(ZipWith0(0, lambda a, b: a + b, self.decimals, y.decimals)).Decimalize(0, True)
    def Difference(self, y):
        yds = Align0(y.decimals, len(self.decimals), 0)
        return LongDecimal(ZipWith0(0, lambda a, b: a + b, self.decimals,list(map(lambda a: 9 - a, yds)))).Decimalize(1, False)
    def Product1(self, y):
	    return LongDecimal(list(map(lambda x: x * y, self.decimals)))
    def Product(self, y):
        return reduce(lambda a, b: a.Sum(b), self.CollectShiftMult(y), LongDecimal([]))
    def LessOrEqual(self, y):
        equal = all(ZipWith0(0, lambda a, b: a == b, self.decimals, y.decimals))
        if equal:
            return False
        else:
            ne_index = (ZipWith0(0, lambda a, b: a == b, self.decimals, y.decimals)).index(False)
            return (ZipWith0(0, lambda a, b: a < b, self.decimals, y.decimals))[ne_index]
    def Print(self):
        res = ""
        count = 0
        for d in self.decimals:
            if count == 1:
                res += "."
            res += str(d)
            count += 1
        return res

class Numbers:
    def __init__(self, number, square_difference, scale):
        self.current_digit = 0
        self.number = number
        self.square_difference = square_difference
        self.scale = scale
    def CurrentDigit(self):
        return self.current_digit
    def GetNextDecimalDigit(self):
        two = LongDecimal([2])
        for dd in range(9, -1, -1):
            zd = LongDecimal([dd]).Shift(self.scale)
            number_sq_diff = self.number.Product(zd).Product(two).Sum(zd.Product(zd))
            if number_sq_diff.LessOrEqual(self.square_difference):
                self.number = self.number.Sum(zd)
                self.square_difference = self.square_difference.Difference(number_sq_diff)
                self.scale += 1
                self.current_digit = dd
                return dd
        return 0

class NumbersGenerator:
    def __init__(self):
        self.generator = self.GenerateDecimal()
    def GetNextDecimalDigit(self):
        return next(self.generator)
    def GenerateDecimal(self):
        number = LongDecimal([])
        square_difference = LongDecimal([3])
        nums = Numbers(number, square_difference, 0)
        while True:
            yield nums.GetNextDecimalDigit()

class NumbersServer:
    def __init__(self):
        self.current_numbers = Numbers(LongDecimal([]), LongDecimal([]), 0)
        self.generator_server = self.GenerateDecimalServer()
    def GetNumbers(self):
        return next(self.generator_server)
    def SetNumbers(self, numbers):
        self.current_numbers = numbers
    def GenerateDecimalServer(self):
        number = LongDecimal([])
        square_difference = LongDecimal([3])
        current_numbers = Numbers(number, square_difference, 0)
        while True:
            yield current_numbers

class Calc:
    def __init__(self):
        self.count = 21
        self.generator = NumbersGenerator()
        self.generator_server = NumbersServer()
        self.result_number = LongDecimal([])
    def RepeatGenerator(self):
        for e in range(self.count):
            zd = LongDecimal([self.generator.GetNextDecimalDigit()]).Shift(e)
            self.result_number = self.result_number.Sum(zd)
        return self.result_number.Print()
    def RepeatServer(self):
        for e in range(self.count):
            numbers = self.generator_server.GetNumbers()
            dd = numbers.GetNextDecimalDigit()
            self.generator_server.SetNumbers(numbers)
            self.result_number = self.result_number.Sum(LongDecimal([dd]).Shift(e))
        return self.result_number.Print()
    def IterateGenerator(self):
        dec = list(Take(self.count, self.generator.GenerateDecimal()))
        return LongDecimal(dec).Print()
    def IterateServer(self):
        number = LongDecimal([])
        square_difference = LongDecimal([3])
        init_numbers = Numbers(number, square_difference, 0)
        init_numbers.GetNextDecimalDigit()
        dec = list(Take(self.count, map(lambda numbers: numbers.CurrentDigit(), Iterate(NextNumbers, init_numbers))))
        return LongDecimal(dec).Print()

def NextNumbers(numbers):
    numbers.GetNextDecimalDigit()
    return numbers

print(Calc().RepeatGenerator())
print(Calc().RepeatServer())
print(Calc().IterateGenerator())
print(Calc().IterateServer())