2024年10月11日金曜日

10000回のループを使って、ちょっとした作業

 fx-CG50 の upython の実行速度に甘えて、ちょっとした作業をやってみました。
数列 1/k の総和を求める作業です。

sum(1/k, k, 1, 10000) という表記をしてみましたが、upython で書けば、こんな作業です。

sum = 0
for k in range(1, 10001) :
   sum = 1/k

1/k 自体が、無限大で 0 に収束するので、「総和も 0 に収束して紅か ?」と考えるのですが、実際には、無限大まで加算すると、発散してしまうのですね。

取り敢えず、10000まで累積総和を計算させてみます。
10000以上にすると、結果はさらに増えていくのですが、この計算、加算の数を多くすると、それにつれて累積数が増えていくのです。
それを「視覚的に」納得しようと。さて、どうするか ?

「手始めに、1から10000までの区間で、グラフを描いたらよかろう !」

グラフ電卓なので、簡単操作でグラフを描いてくれそうですが、実際には、チョット面倒な事になりました。「級数の総和を求める」というのは「関数」で書けません。

そこで、upython のパワーでグラフを描いてみることにしました。
しかし、やってみると解りますが、どうもこの級数和、収束するのかしないのか、はっきりした感じでは掴めません。

そこで「飛び道具」的な手段を導入しましました。対数目盛りのグラフです。
グラフ電卓ですから、対数目盛りのグラフなんかも簡単に描けそうなものですが、実際には、そういった手段が提供されておりません。

そこで、簡単に横軸対数目盛りのグラフを描く、upython スクリプトを用意しました。
このスクリプトを読み込ませると、じわじわと累積して、点を打っていきます。
ループ上限が10000にしてあり、横軸のみを対数目盛りにして、累積数の点を打っておきます (縦横の軸までは描きません) 。

描かれたグラフをみるとわかりますが、それまでは「どこかで伸び悩みそうな累積数のグラフ」が、横軸を対数目盛りにすると、直線になっているのが解ります。
直線ですから、この先、いくらでも増えていくのは想像に難くありません。

こうして、視覚的に納得する事ができました。流行り(?)の「納得と共感」です。

今回も upython の計算速度を利用した「力技」な話題となりました。
こうしたちょっとした計算が手のひらの上で愉しめます。

数学的には、奥深い話題が展開できそうなのですが、その辺りは目下、お勉強の最中なので、機会がありましたらいずれまた、としておきます。

【スクリプト】

from casioplot import *
import math

wi=382
he=191
xs=1
xe=10000
ys=0
ye=10

sum=0
for i in range(xs,xe+1) :
  sum+=1/i
  ii=(math.log10(i)-math.log10(xs))/(math.log10(xe)-math.log10(xs))*wi
  jj=(ye-sum)/(ye-ys)*he
  set_pixel(int(ii),int(jj))
  show_screen()


2024年10月4日金曜日

自家製 copysign() の顛末

 過日、Biomorph for fx-CG50 の記事で、自家製 cmath module を開陳致しました所、K 様から、コメントを頂戴致しました。

K 様の方法で cmath.sqrt() を書くと、計算がスムースに行く上、境界部分での符号の扱いも良い具合になるのですが、残念な事に、fx-CG50 には math.copysign() がなく、適用な手段で代替関数を用意する必要があると、K 様も申されておりました。

そこで、copysign() 風の関数を自作すれば、よかんべ、と調べ始めたのですが、copysign() では、符号チュエックのため、0.0 と -0.0 という値に対応するという話でありますネ。ナニソレ ?

浮動小数点数も符号が用意されているのは解っていたつもりですが、折角だから、0.0 にも符号を付けて、0.0 と -0.0 の2つを用意しよう、という話らしい。
処理系 (コンパイラ) が、ゼロ符号に対応した場合に、python もこれに対応できるらしく、最近のモダンな処理系では、-0.0 という浮動小数点数に対応されている様です。

そんな具合で、我らが fx-CG50 の upython も、-0.0 という数値自体は扱える様に出来ております。
シェルを呼び出して、-0.0 と入力すると、そのもの -0.0 が答えとして返ってきますネ。
しかし、数値としては 0.0 と -0.0 、同じ「ゼロ」でありますから、== で比較すると、True が返ります。何なの、ソレ !?

では、アトムの比較を行う、is で比較をしたら区別が出来るんじゃないか、と思ったのですが、fx-CG50 の場合、これはアカンのですネ。

>>> -0.0 is 0.0 
False
>>> -0.0 is -0.0 
False
>>> 0.0 is 0.0 
False


なんと、0.0 という同じ値を比較しても、False となりますネ。「どうなっとんジャイ、ワレ !」

この謎を解く鍵は、アトムのid を取得する id() でした。

>>> id(-0.0)
2351257904
>>> id(-0.0)
2351258160 
これは一例ですが、同じ操作をしているのに、毎回、id が変化します。

idという値、どうもアトムを保持するheap空間のテーブルインデクス、有り体に言えばポインタの様な値らしい。
これが毎度違う値になるというのは、毎度、浮動小数点数値アトムが振り出されてheapに作られる、という具合の様ですネ。
PCのpython では、0.0 は一意に決まった数値アトムという扱いなので、何度操作しても変化する事はなさそうですが、電卓の方は、そこまで手が回っていないのかも知れません。
( 但し、当方の fx-CG50 upython は、チョット古めです )

こうなると、0.0 と -0.0 の区別は難しいなァ、と思っていたのですが、(数値アトムを)文字列に変換する関数 str() がありました。これを使うと、0.0 , -0.0 、両方とも表示通りに文字列になるのです。これで、0.0 と -0.0 の区別が出来ますネ、ヨカッタ、ヨカッタ。

そんな事が解ったので、自家製の copysign() として、チョット苦し紛れなコードを開陳した次第です。「ご査収ください」

#  copysign() like something ...
def  csign(x, y) :
  if y == 0.0 :
    if str(y) == '-0.0' :
      return -abs(x)
    else :
      return abs(x)
  else :
    if y < 0 :
      return -abs(x)
    else :
      return abs(x)

本来なら math.copysign() と、math module にあるものではありますが、後から追加するわけにも行かないので、自家製cmath module の中に、邪魔にならないよう csign() と名前を変えて導入致しました。

これを使ってcmath.sqrt() もK 様提案の方法にしたのですが、cmat.csign() が足を引っ張っているので、速度は余り期待できません、ハイ。

さて、こうした具合で動いている upython ではありますから、以前に、電卓喫茶様が「fx-CG50 upython で 色指定をタプルで書くと、速度が激落ちする」という報告をされておりました。これは、毎度、数値を含むタプルを生成して、heapに置いているから、時間が掛かっているのではないかという推測をしたのですが、少しは判断材料になったのかも、と思う所です。色指定のタプルを予め作っておき、適当な変数名にbindして、変数を呼び出す様にする事で、オーバーヘッドが大分少なくなる模様です。


2024年9月28日土曜日

fx-CG50 で Biomorph を描く

 Sentaro様から「面白いモノはナーイ ?」との事で、fx-CG50 upython をしばき倒す(?) 「Pickovers' Biomorph」のコードを動かしてみました。

当方が、Pickovers' Biomorph を知った、そのネタ元と言いますと、昔、図書館で読んだ、日経サイエンス誌の連載「コンピューター・リクリエーション」(A. K. Dewdney) なのですが、Pickover biomorphs で検索すると、およその所が解ると思います。

Mandelbrot set graphics の作業の様ですが、少し異なる部分もあります。
詳細はコードをご参照ください。

Pickovers' Biomorphs の場合、繰り返す計算式を色々と変更する事で、描かれる画像が多様に変化します。
このコードでは、

    z = z*z+c
を繰り返しますが、これを、例えばつぎの行にある様に、
    z = cmath.sin(z*z)-c
とかに変更すると、画像が大きく変化するのです。

複素数平面の座標値に数式を繰り返し適用するため、複素数を扱う関数が必要になりますが、残念ながら、fx-CG50 には cmath module が用意されておりません。

そこで、急ごしらえで cmath module を用意しました。 残念ながら、asin() などはまだ、用意できておりませんが、チョット遊ぶなら、この辺りから始めても十分であると思います。 

実行は、プログラムを読み込んだ後、

biom() 

と入力する事で実行されます。

ループ中の数式を変更する事でも、画像が大きく変化するのですが、定数 c を変える事でも、微妙に画像が変化します。
定数 c も複素数ですが、biom(c.real, c.imag) の様に、実部と虚部をカンマで分けて指定する事で与えられます。

残念ながら、cmath module が system binary ではなく、実行速度が大変遅いという哀しい部分はありますが、
じわじわとグラフィクスが描かれる様を眺めるのも、手のひらで動く電卓ならではの愉しみであると思います。

 

追記 on 2024-10-05

過日、K 様にコメント戴き、sqrt() を更新いたしました。
math.copysign() が fx-CG50 には無いため、自家製の copysign() もどき csign() を付け足しましたヨ。これにより、計算速度が向上したという具合には行きませんが、ネタとしては色々と面白かったので、後日、別記したく思います。

謝謝 !


リスト  biom.py

# title : biom.py - Pickovers' Biomorph for fx-CG50
# begin : 2024-09-28 19:33:39

from casioplot import *
import math
import cmath

def  biom(re=0, im=0) :
  width  = 383
  height = 191

  xs=-3.8
  xe= 3.8
  ys=-1.9
  ye= 1.9
 
  c = re - im*1j

  #  Biomorph
  for j in range(height):
    for i in range(width):
      z = (i*(xe-xs)/width +xs) + 1j*(j*(ys-ye)/height+ye)
      #  repeating core
      k = 0
      while abs(z) <= 10 and k < 10:
        z = z*z+c
        #z = cmath.sin(z*z)-c
        k=k+1
      #  
      if abs(z.real) < 10 or abs(z.imag) < 10 :
        set_pixel(int(i), int(j))

      #  show graphix progressively
      show_screen()


リスト  cmath.py

##  title : [WIP] cmath module for fx-CG50
## begin : 2024-09-28 00:38

import math

# copysign() like something ...
def csign(x, y) :
if y == 0.0 :
if str(y) == '-0.0' :
return -abs(x)
else :
return abs(x)
else :
if y < 0 :
return -abs(x)
else :
return abs(x)

#
def phase(x) :
return math.atan2(x.imag, x.real)

##
def exp(x) :
return pow(math.e, x)

##
def ln(x) :
return math.log(abs(x)) + phase(x)*1j

##
def log(x, base=math.e) :
return ln(x) / ln(base)

## thanks K sama ! on 2024-10-04
def sqrt(x) :
# return pow(x, 0.5)
return math.sqrt((abs(z)+z.real)/2) + 1j* csign(math.sqrt((abs(z)-z.real)/2), z.imag)

##
def sin(c) :
return math.sin(c.real)*math.cosh(c.imag) + (math.cos(c.real)*math.sinh(c.imag))*1j

##
def cos(c) :
return math.cos(c.real)*math.cosh(c.imag) - (math.sin(c.real)*math.sinh(c.imag))*1j

##
def tan(c) :
return sin(c) / cos(c)

2024年9月22日日曜日

python電卓を持っていても余り使っておらんので、暇つぶし

 以前に、fx-CG50 を買って、先日、ようやく python が使える様にアップデートした所。
「慣らし運転」ではありませんが、pythonの計算速度を見るつもりで、簡単なループ計算を実行したという次第。

プログラムは以下。
冒頭の文字列部分は「コメント」なので、電卓では無用ノ介。本体のループ部分だけを入れて、実行してみてください。


'''
NHK TV 「3ヶ月で学ぶ数学」より。

問題 : 
3桁の整数 ABC (=100*A+10*B+C) について、
+  ABC * 3/4 = BCA
+  BCA * 3/4 = CAB

の関係を満たす整数ABC は、2つある。全てを求めよ。
(中学校の入試問題より)

答え : 

1. 比例式を準備

+  ABC : BCA = 4 : 3
+  BCA : CAB = 4 : 3

2.  比例式を、最小公倍数にて一本に

+  ABC : BCA = 4 : 3 = 16 :12
+  BCA : CAB = 4 : 3 = 12 : 9

よって、
+  ABC : BCA : CAB = 16 : 12 : 9

3. これより、
   「CAB は 9の倍数」→「CAB の各桁の和は 9 の倍数」→「ABC, BCA の各桁の和は 9 の倍数」

4. また、
   「ABC は 9の倍数 and 16の倍数」→「ABC は 16*9の倍数」

+  16*9 = 144 の倍数
   144, 288, 432, 576, 720, 864

5. 一本化した比例式より、
   A >= B >= C

6.  この条件を満たす 144の倍数は、
    432, 864

という具合であった。

しかし、pythonが動く電卓がある事だし 力技で、解いてみたという次第。
(大人気ない)

結果は、

Hit ! 0
Hit ! 432
Hit ! 864

という具合。
1000回ループながらも、瞬時に答えが得られ、ビックリしてしまいました。

'''

for a in range(10) :
    for b in range(10) :
        for c in range(10) :
            abc = a*100+b*10+c
            bca = 100*b+10*c+a
            cab = c*100+a*10+b
            if abc *3/4 == bca :
                if bca *3/4 == cab :
                    print('Hit !', abc)


2024年8月29日木曜日

プログラム電卓について、色々と考える日々

 前のポストの所で、Sentaro様からのコメントを戴きまして、まだ、色々と考えないとならないことが多いのではありますが、少しだけ思いつきを記しておきたく。

fx-5800Pの改良について

まず、fx-5800Pの機能の一つ「数式記憶機能」について、色々と考えておりました。

fx-5800Pの数式記憶機能、マニュアルをみると、結構気になるものです。
まず、標準で、128の公式があって、これをコピーして編集したり、新規に自前の公式を導入して、ワンタッチで計算できるというものです。
こうした機能、ポケコンの頃から様々用意されておりましたが、fx-5800P秀逸な所は、ギリシャ文字やアルファベットの添字などを使って、表記が柔軟な数式を記入できる所です。一つの到達点に達したかの様なものであります。
しかし、惜しむらくは、この数式記憶機能、そこに囲まれているため、BASICからの利用が出来ない所でしょうか。
BASICでは、別途、プログラムを組めば良いのではありますが、せっかく、ここまで高度な機能があるのなら、縦断して使いたくなります。
まあ、それが難しいというのであれば、この数式記憶でSolverが使えたら、更に面白かったと思うのであります。
128個の数式、というと、結構数が多いように思われますが、1つの計算式について、複数の変量があるため、それらの変量について解いた数式を別個に入れているので、どうしても数式の本数は多くなってしまいます。
数式記憶機能でSolverで使えたら、登録する数式は一本で済みます。これだけで、大分使い勝手がよくなるはず。
欲を言うならば、複数の数式を連立されてSolverで計算できたらいいのでしょうが、そうなると、BASICの仕事、でいいのかも。関数電卓として、数式記憶機能にSolverをつけるだけで、かなり使い勝手が向上しそうです。
ついでに、登録済みの数式についての「副読本」を添付するなどの工夫があれば、学習用途としてもかなり役立ちそうな気がします。

ご一考戴きたく思う次第。

upython電卓の未来像 ?

upython 機能が多くのグラフ電卓に採用される所となりました。

ここで、いくつかの問題があると思われます。

  1. upython が電卓の機能と相互に乗り入れできない
  2.  upython の2進数計算と電卓機能のBCD計算がちがーう
  3.  upython スクリプトの入力、電卓のキーボードでは入力が面倒

1. については、「upython プログラミングの学習用」という位置付けらしく、従来のグラフ電卓機能との分離、やむを得ない所らしい。

例えば、CASIO FX-CG50にて、キーボード real time 入力の検知が出来ないのは、CASIOの方針として「ゲームにうつつを抜かしてはイケナイ」という教育的配慮らしいのですが、これは追々、変化があることを期待したいものです。
また、グラフ電卓部分では、統計処理の所で、t分布などの計算が出来るものの、これらの計算をupython で行うには、gamma function などの特殊関数の機能が必要になりますが、upython 電卓には、こうした関数の計算をするmoduleが提供されておらず、必要と鳴ったら、自前で用意しないとならない。
更に、データを収集して、それをグラフ電卓部分でグラフにしたり、計算処理したりなどですが、upythonにこのデータを持っていったりなどの作業も出来ない、歯がゆさが残ります。

2. については、電卓の計算では、多く1E100までの範囲での計算でしたが、同時に、計算精度も、その範囲内では保証されておりました。電卓側ではBCD (Binary Coded Decimal ;「2進化10進数」)による計算のため、計算精度の保証が出来た様です。
しかし、upython では 実数については2進数のdouble float で計算、もしくは、整数値は多桁整数値の利用が可能で、実数値については、1E320くらいまでは計算でき、計算の範囲は大きく異なります。同時に、2進数floatには、計算についての桁落ちの様な問題もありました。

3. については、電卓というformが根本的に抱える問題でもあり、I/Fの改良による所で、各メーカーは努力を続けております。

こうした問題点を緩和するためには、どうしたらよかんべ ?

1. ですが、upythonのmodule をリッチに追加するしか方策はなさそうです。
例えば、特殊関数のmoudleや、システムよりのmoduleを大量に追加する。
そうして、グラフ電卓部分が不要になる程度に、upython orientedを目指す方向です。

2. については、Sentaro様は「BCDモードをもたせたらいいのではないか」との言葉を寄せていただきました。これが電卓側としては「まっとうな」解決案なのだと思います。
一方で、科学技術計算、特に、sense dataによる科学定数や測定値などには、ある程度の有効桁が存在しており、計算作業の累積で、最後は最も少ない桁数の数値に寄せて、計算精度とする必要があります。そう考えると、double float でも、十分事足りる様でもあります。
幸い、整数の計算については非常に大きな桁数の計算が出来ます。うまくすれば、多桁整数を利用して、手回し計算機の様に桁数の多い計算も可能です。
この際だから、upython電卓としては、BCD計算を止めてしまってもいいのかも知れません。

3. については、電卓のformが抱える根本的な問題でもありますから、極端な話、それこそ、昔のポケコンの様な形状まで検討したら良いのかも知れません。
一方で、高度化する電卓ハードウェアに事寄せて、一つの解決策を提示できるかも知れない。
それは、Bluetooth I/Fの採用です。
Bluetoothを採用する事で、市販のBluetoothキーボードを利用して、upython scriptの入力が軽快に出来る可能性を検討できるのではないか、と。
また、昨今は、Bluetoothで接続できる感熱プリンターなんかもあります。こうしたものを使うと、計算結果やグラフィクスなどを感熱紙に印刷できたりなど、結構夢が広がりますネ !

昔のポケコンやプロ電には、PCに寄せて感熱プリンターなどの周辺機器がありました。
電卓製品になったとしても、こういったものがあったら、それなりに利便があるのではないか、と。


2024年8月11日日曜日

みんなの「憧れ」Mexican Hat

 連日、電卓喫茶 様が、X にて、「Mexican Hat」の作図を複数の電卓で行う作業をポストしておりました。

https://x.com/calculator_cafe/status/1821531729443823776
https://x.com/calculator_cafe/status/1819654869633937426
https://x.com/calculator_cafe/status/1817881332875497881

件のグラフィクス、Mexican Hat というの、寡聞にして知らなかったのですが、確かにとても興味深いものです。
ある世代に、とても「刺さる」ものがあるのですね、この図。昔々の8 bit PC 「MZ-80B」 の広告で、よく見たものです。
Green CRT に(当時としては)精細度の高いグラフィクスで、まさに「コンピューター」による作図、という具合でした。MZ-80B は、当時「高級製品」だったので、ガキの財布で買える様な代物ではありません。憧れの的でした。

同様のグラフィクスが、今では手元の電卓で表示できる、という事を、あらためて示してくれた、電卓喫茶様の一連のポストは、大変嬉しい気持ちでいっぱいになりました。
折角、こうした電卓製品を持っているのであれば、たまにはこうした使い方をしたいものではあります。ハンセイ。

一通りの電卓で作業されているので、今更当方が割って入る隙はなく、外野として、Mexican Hat について少し考えてみたく思います。

Mexican hat は、ある種の関数 z = f(x, y) を、x-y 平面の斜行投影によって 3D作図しているものです。
y 軸方向について「奥」から手前方向に作図することで、陰線処理を実現しているのですが、同時に、この斜行投影という変形によって、作図の面白さが出てくる様でもあります。

左様に、このグラフィクスは3D表示をうまい仕掛けで実現しておりますが、fx-CG50 には、3D グラフ機能がありますネ。
そこで、折角ですから、Mexican Hat の数式を 3D graph で表示してみましょう。ウヒョヒョ !

式は Z = sin(sqrt(X^2+Y^2)) + 0.4*sim(3*sqrt(X^2+Y^2)) の様な表式になります。

X : -4 ... +4, grid=30
Y : -4 ... +4, grid=30

の範囲で描けば、そこそこいい絵が得られる事と思います。
これくらいなら、量販店の店頭に置いてあるデモ機でも十分操作できるので、購入を検討している方は、店頭でお試し頂きたい。

他人様のポストを肴にする程度のことしかできませんで、スマソ。

そういや、Nspire CASのBASICでgraphixが描けないというのは知らんかったですネ。勉強になりました。

あと、藤堂様のpostで、こんなのがありました。

https://x.com/ShunsukeTodo/status/1814566819480674670

「スリーゲイト」でいち早くfx-CG50, Numworks 電卓を販売しておりました、北門 達男氏の書籍紹介です。残念ながらKindle版ですが、一定の需要があるんじゃろうか、Kindle書籍 ?

あと、fx-CG50 のOS アップデータに、Windows 11対応版が出ておりました。

ref. グラフ関数電卓:fx-CG50 OSアップデート
https://support.casio.jp/download.php?cid=004&pid=2126

Windows 11 では「Smart App Control」という仕掛けがあるとかで、コレに対応したアップデータらしい。Windows ユーザーは面倒な事をしないとならない。


2024年8月4日日曜日

fx-CG50 upython で、面白い話をみた

 fx-CG50の upython で、画面の塗りつぶしをすると、ケースによって時間が掛かる場合があるそうです。

電卓喫茶 様の X post 。
https://x.com/calculator_cafe/status/1819663116529275177

色を指定すると極端に時間が掛かるとの事。

確かに、手元のfx-CG50で試したら、極端に時間が掛かっておりました。

しかし、色指定のタプルを変数に入れ、変数で色指定をすると、時間が大きく改善されるようです。

おそらく、ソース埋め込みの定数タプルは、pcode ドライバが毎度interpretするから、時間がかかるのかしらん ?