2025年9月6日土曜日

方程式 solver 試論

 と、格好つけてみましたけれども、大袈裟な物言いの割には、小ネタであったりします。

以前、fx-5800P に、内蔵公式集が 128本くらい入っていると知り、更に、ユーザーによる公式も登録可能、との事で、こうした公式集をダラリと使っていたら、そうした公式に少しは理解が及ぶ所で、初学者の助けになるんじゃないのか、などとボンヤリ思う所でした。

しかし、公式集をみると、例えば、multiple equation solver の様なメカがないため、公式内の変数に対して、式を変形したものが重複して登録されております。

理想を言うならば、公式を一本、入れておいて、Solver が指定した変数に対して数値解を求めてくれる、のが欲しいなぁ、というヘタレぶり。

fx-5800P の様な、公式内蔵のプロ電は、目下、successor が存在せず、というのが実に押井、と思う次第。

fx-CG50 には、Solver Appsがあり、方程式を登録する事で、所望の変数について数値解を計算する事は可能であります。
そこで、Solver Appsに、内蔵公式 selector の様なメカがあると便利かなァ、と思うのありますが、fx-CG50にはもちろんの事、fx-CG100 にも、そうした便利メカは用意されておりません。そりゃそうだ、学校教育向けでしたから、内蔵公式集の様な「あんちょこ」(「安直」の訛りが語源だそうです)は無いのが当たり前でありました。

斯様に、プロ電が「プロツール」の座位から「学校教育向け」に移って行く今日、プロツールの動きとしては、fx-FD10 が最後の輝きだったのか、などと思う所であります。
fx-FD10 が death-continue に至った今日、fx-5800Pが、プロツールの孤塁を守っている、という認識で良いのかも知れません。

プロツールのsuccessor 登場、という局面は期待できない今日、代替製品として、fx-CG50/fx-CG100 の upython に活路を見出すという試みは「密かなる需要、有用性が在りはしまいか ? 」という淡い期待から思いつくのであります。
幸いにして、fx-CG50/CG100 には、スクリプトを沢山抱えるだけのストレージ容量があります。

内蔵公式集として導入されていなくとも、ユーザーが必要な公式を登録、メニュー形式なりで計算式を選択して計算するといった作業を upython scriptとして記録しておけば、十分に活用できそうです。
実際、fx-5800Pに土木計算ライブラリを書き込んだものを、「専用機」として流通している商売があるとの話。

で、ここまでが長すぎる"前フリ"でありました。以降が本題。

fx-CG50/CG100 の Solver Apps, 結構便利なのですが、「方程式セレクタの様なメカが欲しい」という点もさることながら、f(x)=0 の形式の方程式しか解けない、そこが"押井"かなぁ ... と。

で、本編では、upython の計算能を用いて、2元連立方程式の数値解 Solver を模索しようという試みであります。

2方程式の数値解を求めるには、Newton-Rafson 法が利用できるそうで、ここでは簡易版のスクリプトを提示し、読者の皆様 (そんなに居らんのよなァ)に一考願おうという次第です。

つぎのコード「slv2eq.py」を用意します。

```

# title : slv2eq.py - Newton-Rafson Numeric solver
# begin : 2025-08-28 23:25:08 

# mat[2][3]  for equation difference matrix
mat = [ [0 for i in range(3)]  for i in range(2) ]
eps = 1e-9    # machine epsilon

#  pseudo-diff df/dx
def  dfx(f, x, y) :
  #print('debug ... eps ', eps)
  return  (f(x+eps, y)-f(x, y))/eps

#  pseudo-diff df/dy
def  dfy(f, x, y) :
  #print('debug ... eps ', eps)
  return  (f(x, y+eps)-f(x, y))/eps

#  newton-rafson solver
def solvre(f, g, x0, y0) :
  x, y = x0, y0
  for i in range(20) :
    print('.', end='')
    #report(x, y)
    #  
    mat[0][0] =  dfx(f, x, y)
    mat[0][1] =  dfy(f, x, y)
    mat[0][2] =  -f(x, y)
    # 
    mat[1][0] =  dfx(g, x, y)
    mat[1][1] =  dfy(g, x, y)
    mat[1][2] =  -g(x, y)
    # matrix solvre
    d = mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0]
    if d == 0 : 
      d = eps
    tx = ( mat[1][1]*mat[0][2]-mat[0][1]*mat[1][2])/d
    ty = (-mat[1][0]*mat[0][2]+mat[0][0]*mat[1][2])/d
    mat[0][2] = tx
    mat[1][2] = ty

    x += mat[0][2]
    y += mat[1][2]

  print(' END')

  print('x=',x)
  print('y=',y)

  print('eq1()=',f(x, y))
  print('eq2()=',g(x, y))

  return x, y

def report(x, y) :
    print('x = {0:.6f}  '.format(x), end='')
    print('y = {0:.6f}  '.format(y))

def inpnum(str):
  lin=input(str).split(',')
  if len(lin)>1:
    num=complex(float(lin[0]),float(lin[1]))
  else:
    num=float(lin[0])
  return num
```

これを import すると、つぎの2つの関数が利用できます。

  • slv2eq.inpnum()
    数値入力サービス
  • slv2eq.solvre()
    簡易 Newton-Rafson 数値 Solver 

で、使い方としては、

  • 3*x+2*y-3 = 0
  • 3*x-2*y-8 = 0 

の様な方程式を解くため、つぎのスクリプトを実行します。

```

from slv2eq import *

#  equation #1
def f(x, y) :
  return 3*x+2*y-3

#  equation #2
def g(x, y) :
  return 3*x-2*y-8

#  main part
while True :
  x=inpnum('x0= ')
  y=inpnum('y0= ')
  x, y = solvre(f, g, x,y)

```
のようにします。

  1. def で方程式 = 0 の形式で関数定義をして、
  2. slv2eq.inpnum() で 数値解探索を始める初期値入力、
  3. slv2eq.solvre(f, g, x, y) で Newton-Rafson を動かす 

のですが、2, 3 の部分がループになっているのは、初期値の入力が簡単に行え、何度もリトライする為であります。

出力例
```

x0= 1
y0= 1
.................... END
x= 1.833333333333334
y= -1.25
eq1()= 0.0
eq2()= 0.0

```
解の探索を始める初期値 x0,y0 を入力すると、20回ほどの計算の後、数値解を吐き出します。
再び、初期値入力になりますが、この例題では、他に答えがないので、[AC」キーを押して終了します。お疲れ様。

上記の例は、線形2元連立方程式のため、fx-CG50 の Solver Appsでも解けるものでしたが、このスクリプトの威力は、つぎの様な式でも数値解を得られる所です。

  • x*x+9 = 0
  • x-y*y+4*y+4 = 0 

この方程式の場合、数値解が複素数になってしまうので、素直に解けません。
所が、Newton-Rafson 法では、探索を開始する初期値に複素数を用いると、解けてしまうのですネ。コリャーエエ !!

slv2eq.inpnum() では、実数と複素数の入力に対応しております。
複素数の入力をするには、実部のあと「,」を入れ、続けて虚部を入力します。
例えば、初期値に 1-2j を入力するには、1,-2 という入力をします。

実行例
```

x0= 1
y0= 1
.................... END
x= -1.5216944570145454
y= -0.6115683445992836
eq1()= 11.31555402050879
eq2()= -0.3419836755275885
x0= 1,1
y0= 1
.................... END
x= 3j
y= (-0.8761088075138545-0.5215379877427583j)
eq1()= 0j
eq2()= 0j

```

他にも、色々な式が計算できます。しかし、数値計算で、内部で「数値差分」を使うなどしている所から、ピッタリの数値を得られるとは限りません。飽くまでも、正確な値に"にじり寄る"手段として、活用して戴けると幸いです。

何だか、小ネタと書いた割に、長くなってしまい、申し訳ない。

 

【お・ま・け】

HP50G Users guide の Page 7-5 (242) に、Manning 方程式の計算例があります。
これを slv2eq.py の応用例として、書いてみました。コードを示しておきます。

```

# 
# title : manning.py
# begin : 2024-05-13 14:19:41 , 2022-05-11 16:17 
# note  : manning formulae equation solving test.
#       : ex.  cu/n*(y*(b+m*y))**(5/3)/(b+2*y*sqrt(m*m+1))**(2/3)*sqrt(s0) - q  = 0
#       :      y+(q/(y*(b+m*y)))**2/(2*gv) - h0 = 0
#       : ans. q = 20.6614376636849357
#       :      y = 4.9936961327530183
#  

import  math
import  slv2eq

##  variables

#  constants
h0 =  5.0      # represents the energy head (m, or ft) available for a flow at the entrance to a channel
b  =  1.5      # bottom width (m or ft) of channel
m  =  1.0      # the side slope (1V:mH) of the cross section.
n  =  0.012    # Manning   s coefficient, a measure of the channel surface roughness (e.g., for concrete, n = 0.012)
s0 =  0.00001  # slope of the channel bed expressed as a decimal fraction
gv =  32.2     # gravitic accel coefficient
cu =  1.486    # constant for UNIT convinient (ft, yards)

#  equation #1
def  f(q, y) :
  return cu/n * (y*(b+m*y))**(5/3)/(b+2*y*math.sqrt(m*m+1))**(2/3) * math.sqrt(s0) - q 

#  equation #2
def  g(q, y) :
  return y + (q/(y*(b+m*y)))**2/(2*gv) - h0

#  main part

x, y = slv2eq.solvre(f, g, 2, 1)

```


2025年8月31日日曜日

fx-CG50 と fx-CG100 では、何かが違うのかな ?

 金欠で fx-CG50 をポツポツと使って物欲という渇愛を癒やす日々、fx-CG100 を購入の皆様、様々御活用されて居られます様で、ご健勝、お慶び申し上げます。

 Tossy (@Tossy99077342) 様 post より

CASIOのfx-CG100のPython機能のcasioplotモジュールでランダムな色で画面を埋め尽くすサンプル。
何故か描画が途中で遅くなったり速くなったりする。
https://x.com/Tossy99077342/status/1962097774184603800

との事で、簡単なコードを書いてみましたヨ。

from casioplot import *
from random import *

def draw_box(i, j, c) :
  for y in range(16) :
    for x in range(16) :
      set_pixel(i*16+x, j*16+y, c)

for j in range(12) :
  for i in range(24) :
    c = (randint(0,255), randint(0,255), randint(0,255))
    draw_box(i, j, c)
    show_screen()


実行してみると、カラフルな画素で画面を敷き詰める筈。

 fx-CG50 で試したのですが、当方、ジジィになってしまい反射速度も鈍っているらしく、「何故か描画が途中で遅くなったり速くなったりする。」事象を確認するには至らず。

 あるいは、fx-CG100 で実行すると、重大な「何か」で、実行速度に"揺らぎ"が生じたりするものなのかしらん ?

取り敢えず、そんな具合です。お試し戴きましたら、ご報告を戴けると幸いです。


追記 on 2025-09-01

  藤堂俊介 (@ShunsukeTodo) 様のpost がありました。

fx-CG100 虚数の平方根ができるようになったのか。
#CASIO
#関数電卓
https://x.com/ShunsukeTodo/status/1962465220393328693
 

 以前、藤堂様は fx-CG50 の検討をされておられた様ですが、今般、CG100 登場で興味を惹かれたのかも ?

し・か・し ! fx-CG50 でも 複素数の計算はデキルんですヨ ! そりゃ、足りない部分はあるのは否めませんけれども。

 √i, i^i だったら、計算してくれますゼ。Setupでcomplex mode を a+ib にすればヨロシイのです。

 

2025年8月1日金曜日

fx-CG50 : ローレンツ変換の計算にみる、計算精度の問題

 先日、テレビをダラリと見ておりましたら、ローレンツ変換によって、速度 V で移動し続ける事で、時間の流れがゆっくりとなり、結果として「時間の収縮」という現象が生じる、とやっておりました。

具体例として「時速 285km で走行する新幹線に 100万年(!)乗り続けると、1秒だけ時間が縮む」との事。
まあ「100万年も乗り続ける」というのは現実離れした話ではありますが、飽くまでも思考実験であります。
そこで、手持ちの電卓で、宇宙に思いを馳せるが如く、計算してみようという次第。

まだ勉強しているので、詳細は分かりませんが、ローレンツ変換により、つぎの式で時間が収縮する様子が計算される様です。

  t' = t sqrt(1-(v/c)^2)

但し、

  • v  ; 列車の移動速度 (285 km/h)
  • c  ; 光速度  (299792358 m/sec)
  • t  ; 列車に乗っている人の経過時間
  • t' ; ローレンツ変換により、収縮したあとの時間 

これを計算するのですが、まずは多くのグラフ電卓で利用できる upython を使ってみましょう。

import math

c=299792358.0
v=285.0*1000/3600
t=100.0*10000*365.25*24*3600
k=math.sqrt(1.0-(v/c)*(v/c))
td=t*k
print('a{:24.8f}'.format(t))
print('b{:24.8f}'.format(td))
print('d{:24.8f}'.format(t-td))
これくらいならば、どの upython 電卓でも動くでしょう。
実行結果は ...
a 31557600000000.0000
b 31557599999998.8984
d              1.1015

順番に、
(a) 100万年乗車の経過時間
(b) 100万年乗車の経過時間を車両の外部から観測した経過時間
(d)  (a)-(b) の差 ... 時間収縮の量
でありますネ。

テレビの言う通り、ほぼ 1秒程度の時間収縮が得られました。( 100万年走り続けて、これかよ )

計算の共通 platform として、upython を使用しましたが、fx-CG50 の計算機画面(もしくは BASIC)で行ったら、チョットばかりクルシイ結果が ... (a), (b) が同じ値で、(d) = (a)-(b) = 0 になってしまった ... ウーム。


2025年7月10日木曜日

【速報】fx-CG100、遂に日本上陸 !

 先日、「このページなのか ?」と推測のリンクアドレスを上げましたが、2025-07-10, 遂に出現してしまいました ... !

https://www.casio.com/jp/scientific-calculators/product.FX-CG100/

ClassWiz CG というブランドで登場、ちょっとお値段は高めの様子。

いや、思っていたより早くの"上陸"でありました。
これで、fx-CG50 のファームウェア更新はなくなったのでしょうか。残念 ...

  今回は速報なので、以上 !

 追記 on 2025-07-14

そういや、CASIO 電卓の一覧をみて、面白い事に気付きました。

https://www.casio.com/jp/scientific-calculators/#program

先頃、生産完了品となった fx-CG50 ですが、生産完了品になると「オープン価格」になるのネ。
逆に言えば、「オープン価格」にならない fx-5800P は、当面生産が継続される、という見方ができそう。
ClassWizの関数電卓が出ても、programmable な fx-5800P の代替にはならずで、生産が継続されるのも納得ではありますが、個人的にはSolverを改良するとか、やって欲しいの ... 。
 

2025年7月3日木曜日

マイッタなァ、fx-CG50が「生産完了品」になっていたゾ ...

「遂にその日が来た」のでしょうか !? 我らが(?) fx-CG50 が「生産完了品」になっておりました ! ガーン !!

ref. グラフ関数電卓 fx-CG50 - casio.com
https://www.casio.com/jp/scientific-calculators/product.FX-CG50/

生産完了品、と銘打っている以上、つぎの推移が予想されます。マイッタ。

1. fx-CG50 の後継製品 (fx-CG100 ?) の登場、もしくは グラフ電卓自体の終売
2. 生産完了品 (fx-CG50) に対するアップデート提供の終了

ウーム、コマッタ ... 。

一方、Add-Ons にて開発が進められている PythonExtra が、0.4 に更新されておりました。
どうも、対応機種の拡大と、upython の更新が目玉となっているようです。

ref. Lephenixnoir/PythonExtra - git.planetcasio.com
https://git.planet-casio.com/Lephenixnoir/PythonExtra/releases

対応機種の拡大ですが、タッチパネル・CAS付きの fx-CP400, fx-CG500 への対応と、GRAPH MATH+ への対応が謳われておりますネ。GRAPH MATH+ も Add-Ons に対応している、という具合なのでしょうか ? すると、fx-CG100 でも Add-Ons が稼働する可能性が見えてきた ... ? 

fx-CG50のファーム更新が途絶しても、PythonExtra という「逃げ道」があるのは、救いでもあるのでしょうか。

折角、こうした成果物があるというのに、まともなコードを書けずにいる、不甲斐なさよ ...


2025年6月2日月曜日

fx-CG50 の最終アップデートから 1年以上経ちました

以下のページをご覧頂きたく。 

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

fx-CG50 のアップデーターですが、最終版の Version 3.80.XX1X が公開された 2024年4月24日から、1年以上が過ぎております。
(2024年8月6日のアップデーターは、Windows Smart App Control 対応版なので、内容は不変 )

Graph MATH+, fx-CG100 が海外で発売されている所で、upython の version が 1.9.4 と fx-CG50 と同じという事なので、

Graph MATH+, fx-CG100 と fx-CG50 は 同じ upython だから、fx-CG50 のアプデは終了ネ ! 日本でも fx-CG100 を発売するから、それを買ってチョ !!

 だったりしたら、サミシイなァ。

 せめて、getkey() くらいは追加して欲しいのヨ。

でも、ゲームプログラム とか書いた事がないから判らんのだけれど、最近のゲームプログラムって、イベントドリブンな構造だったりするのか ? 

loop 内で getkey() でキー入力検出と分岐処理というsingle thread, 手続き型ループ処理だと「もたつくからイヤ」とか贅沢な事を言ったりして ? fxCG50 の upython 実行速度は結構早いと思うので、あとは工夫の問題なのか、と思ってみたり。

まあ、「無駄口叩く前に、面白いコードでも書けや」 と言われたら、ぐうの音も出ません、オソマツ !

 

2025年5月27日火曜日

fx-CG50 : カッシーニの卵形線を描いてみるゾ

 前に「カッシーニの卵形線」というのがあると聞いたので、手持ちの fx-CG50 upython で描いてみた、という小ネタです。

ref. カッシーニの卵形線 - Wikipedia
https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%83%E3%82%B7%E3%83%BC%E3%83%8B%E3%81%AE%E5%8D%B5%E5%BD%A2%E7%B7%9A

 

2025-06-01 追記

やす親分から、線引きなどの機能を実現した module「u.py」のお知らせを戴きまして、大いに刺激を受け、改変致しました。親分、お世話になります ! 

 

こちらのページから u.py を取得して、導入しておいて下さい。 

ref. Casio Python - ユーザー関数 line() - e-Gadget 様
https://egadget.blog.fc2.com/?no=764

 

座標軸の表示を盛り込みましたが、「目盛り」は盛り込んでおらんです。いずれの課題としておきます。

代わりに、デカルトの正葉線の式を追加致しました。 

また、表示領域の指定をチョット凝るなどしております。

元々、関数の絶対値が指定の値よりも小さい時に 0 とみなして、点を打つ具合に動作しておりますから、正確な線と較べると、太くなってしまう所がります。

デカルトの正葉線のWikipedia をみると、媒介関数表示が出来るので、 fx-CG50 のグラフ機能できれいな線を描けます。比較してみると面白いと思います。

 

ref. デカルトの正葉線 - Wikipedia
https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%AB%E3%83%AB%E3%83%88%E3%81%AE%E6%AD%A3%E8%91%89%E7%B7%9A

  

upython のコード ( 改訂新版 : やす親分の u.py module を使用します)

 
from u import *
from casioplot import *

#
def f(x,y):
return (x*x+y*y)*(x*x+y*y)-2*(x*x-y*y)-(1.02**4-1**4)

#
def f1(x,y):
return x*x*x-3*x*y-y*y*y

#
def scrSize() :
if isCG() :
return 384, 192
else :
return 384/3, 192/3

#
def axis(xs,xe,ys,ye):
i = int(-xs/(xe-xs)*width)
j = int(-ye/(ys-ye)*height)
line(0,j,width,j)
line(i,0,i,height)

#
def draw(func,xs,xe,ys,ye,eps):
for j in range(height):
for i in range(width):
x = (i*(xe-xs)/width +xs)
y = (j*(ys-ye)/height+ye)
if abs(func(x,y))<eps:
set_pixel(i,j)
# show graphix progressively
show_screen()


# main part
width, height = scrSize()
#xs,xe,ys,ye= -1.6,1.8,-0.7,0.9
xs,xe,ys,ye= -2.4,2.7,-1.05,1.35
eps=0.05

draw(f,xs,xe,ys,ye,eps)
axis(xs,xe,ys,ye)
 

( 参考 : 最初のコード )

 
 from casioplot import *
#
def f(x,y):
  return (x*x+y*y)*(x*x+y*y)-2*(x*x-y*y)-(1.02**4-1**4)


def draw():
  width  = 383
  height = 191

  xs=-1.8
  xe= 1.8
  ys=-0.9
  ye= 0.9
  eps=0.05

  for j in range(height):
    for i in range(width):
      x = (i*(xe-xs)/width +xs)
      y = (j*(ys-ye)/height+ye)
      if abs(f(x,y))<eps:
        set_pixel(i,j)
      #  show graphix progressively
      show_screen()
        
draw()