#!/usr/local/bin/python # coding: iso-8859-1 # Copyright © 2008 by Amos Newcombe # # This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with this program. If not, see . '''Command-line program to calculate greatest common divisors. ''' def gcd(nA, nB): # Euclid's algorithm while nB: nA, nB = nB, nA % nB return nA def gcdEuclidRecursive(nA, nB): if nB == 0: return nA return gcdEuclidRecursive(nB, nA % nB) def gcdLRA(nA, nB): while nB: nR = nA % nB if ( nR > (nB >> 1)): nR = nB - nR nA, nB = nB, nR return nA def gcdLRA2(nA, nB): while nB: nR = nA % nB if ( nR > (nB // 2)): nR = nB - nR nA, nB = nB, nR return nA def gcdRSB(nA, nB): # find even part nExp2 = 0 while not ((nA | nB) & 1): nA >>= 1 nB >>= 1 nExp2 += 1 # remove extra factors of 2 while not (nA & 1): nA >>= 1 while not (nB & 1): nB >>= 1 # find odd part while nA != nB: if nA < nB: nA, nB = nB, nA nA -= nB while not (nA & 1): nA >>= 1 return nA << nExp2 def gcdRSB2(nA, nB): # find even part n2 = 1 while not ((nA | nB) % 2): nA //= 2 nB //= 2 n2 *= 2 # remove extra factors of 2 while not (nA & 1): nA //= 2 while not (nB & 1): nB //= 2 # find odd part while nA != nB: if nA < nB: nA, nB = nB, nA nA -= nB while not (nA & 1): nA //= 2 return nA * n2 def gcdLSB(nA, nB): if nA < nB: nA, nB = nB, nA while nB > 0: nExp2, nBT, nBT1 = 0, nB, nB << 1 # invariant: nBT, nBT1 = nB * 2^nExp2, nB * 2^(nExp2+1) while nBT1 < nA: nExp2 += 1 nBT = nBT1 nBT1 <<= 1 # nBT <= nA < nBT1 nA = min(nA - nBT, nBT1 - nA) if nA < nB: nA, nB = nB, nA return nA def gcdLSB2(nA, nB): if nA < nB: nA, nB = nB, nA while nB > 0: nExp2, nBT, nBT1 = 0, nB, nB * 2 # invariant: nBT, nBT1 = nB * 2^nExp2, nB * 2^(nExp2+1) while nBT1 < nA: nExp2 += 1 nBT = nBT1 nBT1 *= 2 # nBT <= nA < nBT1 nA = min(nA - nBT, nBT1 - nA) if nA < nB: nA, nB = nB, nA return nA dfGcd = { 'E': gcd, 'C': gcdEuclidRecursive, 'N': gcdLRA, 'R': gcdRSB, 'L': gcdLSB, 'n': gcdLRA2, 'r': gcdRSB2, 'l': gcdLSB2, } def gcdlist(fGcd, ln): # print 'gcdlist(%s, %s)' % (`fGcd`, ln) if isinstance(fGcd, str) and fGcd: fGcd = dfGcd.get(fGcd[0], gcd) if not ln: return 0 nResult, ln = ln[0], ln[1:] while ln: n, ln = ln[0], ln[1:] nResult = fGcd(n, nResult) return nResult from commander.commander import commander import sys class CmdGcd(commander): # ¤ Creation def __init__(self, lsLine, sName): self.sUsage = '''\ python %%prog n1 n2 ... Write the %s of the arguments to standard output. "No bitshift" use multiplication, division and modulo by 2 instead of bit shift and test.\ ''' % sName self.sVersion = '%prog 2008.08.05.0' commander.__init__(self, lsLine) def options(self): # called by commander.__init__() 'populate the option parser (self.optParser) with options' # print 'options()' nVerbDef = 0 # default verbose level self.sAlgDef = 'E' self.optParser.add_option('-v', '--verbose', action='store', dest='nVerbose', type='int', default=nVerbDef, metavar='N', help='set the verbosity to N (default %d)' % nVerbDef ) self.optParser.add_option('-i', action='store_true', dest='isStdIn', help='get further input from stdin', ) self.optParser.add_option('-E', action='store_const', dest='sAlg', const='E', help='use Euclid\'s algorithm (default)' ) self.optParser.add_option('-C', action='store_const', dest='sAlg', const='C', help='use Euclid\'s recursive algorithm' ) self.optParser.add_option('-N', action='store_const', dest='sAlg', const='N', help='use Euclid\'s algorithm, allowing negative remainders' ) self.optParser.add_option('-n', action='store_const', dest='sAlg', const='n', help='use Euclid\'s algorithm, allowing negative remainders, no bitshift' ) self.optParser.add_option('-R', action='store_const', dest='sAlg', const='R', help='use the Right shift binary algorithm' ) self.optParser.add_option('-r', action='store_const', dest='sAlg', const='r', help='use the Right shift binary algorithm, no bitshift' ) self.optParser.add_option('-L', action='store_const', dest='sAlg', const='L', help='use the Left shift binary algorithm' ) self.optParser.add_option('-l', action='store_const', dest='sAlg', const='l', help='use the Left shift binary algorithm, no bitshift' ) # ¤ Operation def main(self, df, sAbbr): f = df.get(self.opt.sAlg, df[self.sAlgDef]) nResult = 0 for s in self.CommanderArgs(self.lsArgs, self.opt.isStdIn): if 2 <= self.opt.nVerbose: print '%s%s(%s, %d) =' % (sAbbr, self.opt.sAlg or self.sAlgDef, s, nResult), try: nResult = f(int(s), nResult) except ValueError: continue if 1 <= self.opt.nVerbose: print nResult print nResult class CommanderArgs: def __init__(self, ls, isStdIn): self.ls = ls self.isStdIn = isStdIn def __iter__(self): return self def next(self): if self.ls: s, self.ls = self.ls[0], self.ls[1:] return s elif self.isStdIn: self.ls = sys.stdin.next().split() return self.next() else: raise StopIteration if __name__ == '__main__': CmdGcd(sys.argv, 'greatest common divisor').main(dfGcd, 'gcd')