clacは使えるよ!

簡単な計算をするときに長らく重宝していたのがcalcというソフト。コマンドラインから十分な精度で計算してくれる。非常に便利で、私はここ数年というもの、毎日のように使っていた。

  • calc "9**100"
    265613988875874769338781322035779626829233452653394495974574961739092490901302182994384699044001
  • calc 1/10
    0.1
  • calc "sqrt(2)"
    1.4142135623730950488

別にPython起動してもいいんですけどね。シェルの入力でそのまま計算できるというのは便利なもんです。

しかしFedoraならいいけど、EPELにパッケージがないのでCentOSでは使いにくいという問題があった。しょうがないので自分でrpm作って入れてたんです。

そこに登場したのがPythonのeval()をうまく使ったclacというソフト。似たような使い勝手で、Pythonなので無限桁の整数を苦もなく使える。拡張もやりやすい。ソースはPythonのスクリプト1本なので、Cygwinのような環境にも持ち歩ける(Cygwinのパッケージには入ってませんが)。

これは良い! 非常に!!

…のだけど、

  • clac "9**100"
    265613988875874769338781322035779626829233452653394495974574961739092490901302182994384699044001
  • clac 1/10
    0.10000000000000001
  • clac "sqrt(2)"
    1.4142135623730951

うーむ。浮動小数点の演算で誤差が入るのはどうもアレですよねー。

しかし、拡張可能というのがこういう時に使えることを私は知っている。Pythonには分数や10進演算のモジュールがある。分数は確かPython 2.7以降だから入ってない古い環境もあるかもしれないが。なので、~/.clacrcに以下のように書いておく。

try:
  from fractions import Fraction
  frac=Fraction
except ImportError,detail:
  #old python
  pass
from decimal import Decimal
dec=Decimal

これによって、正確に計算することができるのだ。

  • clac "dec(1)/10"

    0.1
  • clac "frac(1)/10"

    1/10

ちょっと変な計算だってできる。まああまりに凝ったものならPythonを起動したほうがゴニョゴニョ…

  • clac "min(3,2,5)"

    2
  • clac "map(lambda f: f**2, [5,2,3])"

    25,4,9

16進数や2進数での出力も。Pythonのバージョンが古いと2進数はダメですが。

  • clac "bin(10**10)"

    0b1001010100000010111110010000000000
  • clac "hex(99979**20)"

    0x12360D70241827049F39B016F8F033F71E6CA4C37A526FFE06BB97EB9CEEC0FBBAF2F203830C74DAFDF1L

例えば、N進数の表示をする関数を定義しても良いだろう。

def nary(v, n=10):
  import string
  nary_digits=string.digits+string.ascii_lowercase
  assert(len(nary_digits)>=n)
  r=[]
  while v!=0:
    r.append(nary_digits[int(v%n)])
    v=long(v/n)
  r.reverse()
  return "".join(r)
  • clac "hex(10**10)"

    0x2540BE400L
  • clac "nary(10**10, 16)"

    2540be400
  • clac "nary(10**10, 30)"   ← 30進数

    dlfkb3a

でも、clacの環境だとこのnary()、可哀想にどこかで浮動小数点数に変わってしまうみたいで、桁数が多くなるとダメです。普通にPythonの関数として呼ぶと大丈夫なんですけどね…なんだかなぁ。

  • Python>>> nary(99979**20, 16)

    12360d70241827049f39b016f8f033f71e6ca4c37a526ffe06bb97eb9ceec0fbbaf2f203830c74dafdf1
  • clac "hex(99979**20)"

    0x12360D70241827049F39B016F8F033F71E6CA4C37A526FFE06BB97EB9CEEC0FBBAF2F203830C74DAFDF1L
  • clac "nary(99979**20, 16)"

    12360d702418270000000000000000000000000000000000000000000000000000000000000000000001

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です