__int64 a, b ; // アンパック BCD
__int64 c = 0xF6F6F6F6F6F6F6F6, d = 0x0505050505050505,
e = 0x0606060606060606, f = 0x0A0A0A0A0A0A0A0A, g = 0x0F0F0F0F0F0F0F0F ;
__asm
{
movq mm0, a
movq mm1, b
movq mm4, f
paddb mm0, mm1
pcmpgtb mm4, mm0
paddq mm0, c
pand mm0, g
movq mm1, mm0
pcmpgtb mm0, d
pand mm4, mm0
pand mm4, e
psubb mm1, mm4
movq a, mm1 ; a ← result
}
a, b が、上位4ビットに3が入っている形式の場合には c の値を修正するだけでOKのはずです。
また、a - b をするには、b = f - b を計算してから加算すればOKかな…?
因みにキャリーに paddq を使っているので、SSE2 以降ですね、このコードだと。
金の計算と帳票処理なら (スコア:0)
二進化十進 (スコア:1)
良いものは良い。
なんか文句がある人がいるんでしょうか。
Re: (スコア:0)
Re:二進化十進 (スコア:1)
# ただしCOBOLを実装するに当たって有用かどうかは知らない :p
Re: (スコア:0)
使ったことないし詳しくは知らないが。
Re: (スコア:0)
#全命令の内、これだけなかった。確かになくてもあまり困らんかったが。
Re:二進化十進 (スコア:1)
小数点未満は四捨五入で。
Excelと電卓は16157円になった。
Re:二進化十進 (スコア:1, 興味深い)
では次の問題はどうでしょう。COBOL でも Java の BigDecimal でも、記述の面倒さは同程度かと思われます。
単価 123円45銭 数量 678円のときの金額を求めよ。ただし、 金額が 1万円以上の場合は、100円未満は四捨五入。
Re:二進化十進 (スコア:1, すばらしい洞察)
Re: (スコア:0)
絶対に許されないことはありません。
ひょっこりひょうたん島のトラヒゲデパートでは、現金を商品として売っていました。数量の単位として円もありえます。
Re: (スコア:0)
商品名は百円玉で、数量の単位は個が妥当です。
# 百円玉一個ありました
Re: (スコア:0)
IBM互換機(オフトピ) (スコア:1)
PC/ATを思い出す人とどっちが多いんでしょ?
後者は最近ではWindows互換機と呼ぶことが多い?
-- う~ん、バッドノウハウ?
Re: (スコア:0)
前者は使ったことないから知らん。ACOSは互換じゃなかったので。
N社のCOBOLプリプロセッサのCOBOL/Sは結構面白かったな。
Re: (スコア:0)
Re:二進化十進 (スコア:3, おもしろおかしい)
10 シキ SUM=0
20 マワレ 40 I=1 カラ 10000 カンカク 1
30 シキ SUM=SUM+0.1
40 トジル
50 カケ 1,SUM
60 オワリ
・・・しまった、「ジッコウ」しようにももう実機もってない・・・。
Re:二進化十進 (スコア:2, すばらしい洞察)
Re:二進化十進 (スコア:1)
内部10進演算を行うBASICだもんね。
Z80なのによくやるよ。
(おかげで実行速度は犠牲になってますが)
Re:二進化十進 (スコア:1)
そういうCPUでソフトウェアで小数の演算を実装する分には、10進にしてもそれほど速度的なオーバヘッドは無いと思います。
通常の加減算は16bit演算できるのに対しBCDだと8bit演算しなきゃいけないので、多倍長演算をするのに加減算の手間が二倍になるオーバーヘッドが大きいでしょう。でも、乗除算演算を実装する場合には、それ以外の処理が大多数を占めますし、それよりも、プログラマの腕(コードの質)の方が支配的でしょう。
内部10進をデメリットとしては、速度よりもメモリ的なオーバヘッドの方が大きいような気がします。
Re: (スコア:0)
と不思議に思った数秒後に、
FP-1100のBASICは10進演算していたのを思い出した。(だから遅かったよNE!)
・・・懐かしい思い出をありがとう。
Re:二進化十進 (スコア:1)
Z-80にもDAA命令があるのでBCD演算の実装はまあ、浮動小数の実装と比べて、
そんなに極端な差は出ないと踏んだんでしょうけど、
MSXのユーザーの大半は使ってなかったと言う…。
あと懐かしいといえばNCB(Number Crunch BASIC)てのもありましたねー。
ナンバークランチングをBASICでやろうと言うのも凄い話なんですが(^^;
とにかくBCDを実装した言語はパソコンにも割とあったと言うお話です。
ちなみにIA-32のSIMD命令にもちゃんとBCD演算を考慮した命令(四則演算)は残ってますし、
IBMメインフレームじゃなくても、実装は十分出来ると思うんですけどね。
だいたい、BCDじゃなくても、有効桁数がある程度設計で見えているなら、
64ビット整数で固定小数点演算にすれば、誤差は少ないですからJavaで何が悪い、
と言う事にもなるんでしょうね。
言語選択より、計算精度なんてもともとプログラミング時にプログラマが設計すべきものでしょ。
なので、COBOLである必要性、と言うと…書式が厳密。と言う点はあるかもしれないですが、
BCD演算に優位性がある、と言われると、うーんと考えてしまいます…。
Re: (スコア:0)
正気の沙汰ではありませんね。
ひょっとして御社ではそれでシステムの設計をなさってる…?
Re:二進化十進 (スコア:1)
極端な例を書けば、MPEGビットストリームでは各パートごとに有効ビット数がありますし、
ゲーム機の演算ハードウェアは有効ビット数が決まってます。
いや、それ以前にアセンブラ使うならレジスタのビット長をちゃんと把握して無いと計算できませんよ?
C/C++を使う場合も、自分の使っている演算長はちゃんと把握していないと固定小数点演算なんて、
アンダーフローやオーバーフローをバリバリ出してあっという間に計算が破綻するなんて割とざらですが?
FloatやDoubleだって、有効ビット数を考えて居ないと、たとえば演算で回転変換をかけたりすると、
数回転しただけで破綻しますよ。
・・・そこまで極端な事を言わなくても、たとえば、浮動小数を使っている、と言う自覚があれば、
当然誤差の含まれた計算をしている、という意識が働くわけで、数値を==で比較する、なんて、
阿呆なコードは書かないわけで、(NANや初期化直後の0とかは除いて…)、いずれにしろ、これも
「演算精度をプログラマが自覚している」って事でしょ?
むしろ上記を考えない、と言うのはプログラマとして大問題を抱えてるのではないですか?
Re: (スコア:0)
> むしろ上記を考えない、と言うのはプログラマとして大問題を抱えてるのではないですか?
当然プログラマは精度等について自覚している必要はあります。
でもそれは
> 計算精度なんてもともとプログラミング時にプログラマが設計すべきものでしょ。
とは何の関係もないことです。
普通の会社では、精度は「プログラミングよりずっと前に」「むしろプログラマ以外の人が」設計するものですが、ホント。
あなたがたは与えられた精度を満たすようなコードを書いているだけで、設計時の精度の決定には噛んだ経験はなさそう、
もしくは、愚か者ゆえにそこから何も学ばなかった(ベンジャミン・フランクリン)ようですね。
Re:二進化十進 (スコア:1)
IA32のSIMDにBCD命令って何かありましたっけ?
もちろん、整数演算でBCDを実現することは不可能ではないでしょうけど…
Re:二進化十進 (スコア:1)
Re:二進化十進 (スコア:1)
FPUおよびCPU一般命令でBCDを扱う命令がありますの間違いです。
ちなみにSIMDでBCDは全く扱えないか、と言うと、工夫次第である程度はいけそうです。
整数で実現する方法はと言うと、BCDを実現するには
ハーフキャリー(ハーフボロー)を監視すればよいのですが、
SIMDだけでやるとアンパックして、更にビットをずらしてまたアンパック後に、
比較命令でマスク生成してマスクを4ビットずらして加算してパックして更にパック。…と、面倒くさいですね。
失礼しましたです。
Re:二進化十進 (スコア:1)
加算だと
a, b が、上位4ビットに3が入っている形式の場合には c の値を修正するだけでOKのはずです。
また、a - b をするには、b = f - b を計算してから加算すればOKかな…?
因みにキャリーに paddq を使っているので、SSE2 以降ですね、このコードだと。
Re:二進化十進 (スコア:1)
>また、a - b をするには、b = f - b を計算してから加算すればOKかな…?
b = 0x090909090909090A - b が正解かな?(汗
ま、いないとは思いますが、使う場合には自己責任でちゃんと動作チェックを…(^^;;;
確信犯 (スコア:1, 参考になる)
おまけ
Re: (スコア:0)
Re: (スコア:0)
Re: (スコア:0)
for i=1 to 10000
temp = temp + 0.1
next
wscript.echo temp
C:\Documents and Settings\Anonymous_Coward\デスクトップ>cscript /nologo 10000.vbs
1000.00000000016
Re:二進化十進 (スコア:1)
from decimal import *
print sum(Decimal('0.1') for i in xrange(10000))
$ python a.py
1000.0
Re:二進化十進 (スコア:1)
普通に1000になりますが。
Re:二進化十進 (スコア:1)
問: リンゴが0.1個入った袋が全部で10000個あります。リンゴは全部で何個分あるでしょうか。
答: 1000個分
余裕です。
問: 猫が0.1匹入った袋が全部で10000個あります。猫は全部で何匹分あるでしょうか。
答: 1000匹ぶ……、いや待てよ。袋の中身が首ばっかりなら10000びk…、うわぁああああ。
感情に流されず淡々と仕事をこなす。COBOLはやっぱりすげえや。
Re:二進化十進 (スコア:1)
# 本当に実行すると10000行エラーが出るので注意。自分はループ10回で構文チェックしました。
しょうがないので man dc して dc を使おう。 うう、夢幻ループになったかと思った。これ、有効数字が小数第1位までだから正しく見えるのかな?
Re: (スコア:0)
Re: (スコア:0)
ちゃんと1000になります(><
Private Sub Form_Load()
d@ = 0@
For i = 1 To 10000
d@ = d@ + 0.1@
Next
Debug.Print d@
End Sub
# いや、冗談ですよ?
Re: (スコア:0)
% cat a.rb
require 'bigdecimal'
a = BigDecimal("0.1")
sum = BigDecimal("0")
10000.times(){ sum += a; }
puts sum.to_i
% ruby a.rb
1000
# 次はどの言語だ?
Re: (スコア:0)
1000.00000000016
Re: (スコア:0)
1000.000000
Re: (スコア:0)
Re: (スコア:0)
Re:二進化十進 (スコア:1)
BCD演算の出来ないMPUならそこら中にあります。(T/O) (スコア:1)
Re: (スコア:0)
それらのハードウェアに合わせてCOBOLが実装されたのではなく、それらのハードウェアとCOBOLは同じ目的を持ってデザインされたんだよ。