ab.com コミュニティ

ActiveBasicを通したコミュニケーション
現在時刻 - 2018年10月22日(月) 22:46

All times are UTC+09:00




新しいトピックを投稿する  トピックへ返信する  [ 8 件の記事 ] 
作成者 メッセージ
投稿記事Posted: 2010年4月25日(日) 07:56 
変数の型を最適化してスピードアップを図りたいと思っています。

現在は、Integer型を使用していますが、変数の置き換え、計算等を数多くするので、Char型が有利であろうと考えました。

しかし、一部の計算でChar型を超えてしまう計算が含まれているので、その箇所をIntegerに変換しながら計算する手法としてみました。

しかし、その「変換しながら」にコストがかかってしまい、本末転倒と言いますか、今ひとつの結果になってしまいました。

以下のサンプルで、「*TEST01-00」がInteger同士の計算
「*TEST01-02」がChar型からIntegerへ変換しながらの計算です。

もっと、効率的(スピード的に有利な)方法が、あったらご教授いただければと存じます。

宜しくお願いいたします。

コード:
#N88BASIC

	Dim P%[9,9,59] AS Integer
	Dim R%[9,9,59] AS Char
	Dim TA1%	 AS Integer
	Dim X		 AS Char
	Dim Y		 AS Char
	Dim I$ AS STRING
	Dim dwStart AS int64
	Dim dwEnd AS int64
	Dim TIMECOUNT AS int64
	Dim CT AS Int64
	Dim CT2 AS Int64
	Dim N AS Char


	N=1	

	Randomize

	FOR X=1 TO 8
		FOR Y=1 TO 8
			P%(X,Y,N)=Int(Rnd()*3)
			R%(X,Y,N)=P%(X,Y,N) AS Char
		NEXT
	NEXT

	PRINT "計算スピードテスト"
	CT2=20000000
	Print 


	Print "Integer(通常)"
	dwStart = GetTickCount()
	FOR CT=0 TO CT2:GOSUB *TEST01-00:NEXT
	PRINT TA1%
	GOSUB *TIMEPRINT

	Print "Char(Integerへ変換しながら計算)"
	dwStart = GetTickCount()
	FOR CT=0 TO CT2:GOSUB *TEST01-02:NEXT
	PRINT TA1%
	GOSUB *TIMEPRINT

	I$=Input$(1)
	END

*TIMEPRINT
	dwEnd = GetTickCount()
	TIMECOUNT=(dwEnd-dwStart)/100 
	PRINT TIMECOUNT/10;"秒" 
	RETURN

*TEST01-00
	TA1%=P%[1,1,N]+P%[1,2,N]*3+P%[1,3,N]*9+P%[1,4,N]*27+P%[1,5,N]*81+P%[1,6,N]*243+P%[1,7,N]*729+P%[1,8,N]*2187
	RETURN

*TEST01-01 '遅いのでボツ
	TA1%=(((((((P%[1,8,N]*3+P%[1,7,N])*3+P%[1,6,N])*3+P%[1,5,N])*3+P%[1,4,N])*3+P%[1,3,N])*3+P%[1,2,N])*3+P%[1,1,N])

*TEST01-02
	TA1%=R%[1,1,N] AS Integer+R%[1,2,N] AS Integer*3+R%[1,3,N] AS Integer*9+R%[1,4,N] AS Integer*27+R%[1,5,N] AS Integer*81+R%[1,6,N] AS Integer*243+R%[1,7,N] AS Integer*729+R%[1,8,N] AS Integer*2187
	RETURN

[/quote]


通報する
ページトップ
   
投稿記事Posted: 2010年4月25日(日) 07:58 
申し訳ありません。
投稿に名前を入力し忘れてしまいました。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2010年4月25日(日) 14:53 
読む気も失せるコードで見てないけど、なんでCharが速いと思ったのだろうか。

どのCPUかわからないけど、32ビットなら32ビット型を54ビットなら64ビット型を使えばいい。


そもそもほんとうにスピードが必要なら、型による速度よりも計算量に気をくばるべきだし、
ABを使うなといいたい。もっと速度の出る処理系を使うべき。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2010年4月25日(日) 16:33 
「読む気も失せる」コードで、申し訳ないです。
(これでも、シンプルにしたつもりです)

>なんでCharが速いと思ったのだろうか。
どんなCPUであれ、16Bitより8Bitの方が処理速度について有利だと思ったからです。
違っています?何だかトンチンカンな質問になってしまっているみたいですね。
ごめんなさい。

>計算量に気をくばるべきだし、
もちろん、計算量や計算式の最適化も考えています。
それもやりつつ、型による処理速度向上を考えたわけです。

>ABを使うなといいたい
すみません。唯一(どうにか)使えるのがABなのです。


通報する
ページトップ
   
投稿記事Posted: 2010年5月08日(土) 02:12 
こんばんは。

おそらく、実験的な事を繰り返して頭を捏ねているのかなと勝手に推察します。
云十年前はじめてパソコンに触れていた頃に同じような事をいっぱいしました。
回答だと決め付けられたプログラムを勉強するのではなく
自ら回答を探すからこそ、発想が思わぬ回答を持ち出して愉快になることが
多々あるかと思います。
しかし、トモカズさんは大人ですね。。。これからも頑張ってください。

さてさて、計算速度を上げたいとの事ですが
多次元配列は、何をするにも遅いと聞いた事があります。
ですので、まず第一に多次元配列ではない方法でも実験をされてはいかがでしょうか。
あと、このプログラムを組み込んで行く先の都合にもよりますが、
式を見ると計算の桁数がとても多くなりますね。ですので
必要な時に必要な部分だけ計算をするのも体感速度を上げてくれます。
また、数式を出来るだけ計算しておいてあげるのも一つだと思います。
(x*2)*(x*3)のような式であれば、これを展開しておいたほうが速いかもしれません。

私が、速度を上げる時はパソコン任せの部分を人間が管理することで
パソコンの負担を減らしてやるってのが良くやる手です。

多次元でも、メモリの並びは一直線上に並んでいるものと考えて良いそうです。
(10,10)の多次元で(0,0)の場所が0番地だとすると
(0,1)は1番地、(0,2)は2番地、(0,9)は9番地となって次の
(1,0)は10番地という感じだそうです。
この(x、y)座標とでもいいましょうか。これをメモリの位置に置き換えてくれている分
パソコンは別の仕事をしているようです。
なので、
HeapAllocでメモリを確保して、どこに書き込むかは人間側で計算し管理して
書き込んでいきます。計算もそうやってすることでちょっとは早くなるかもしれませんよ。
確保したメモリはHeapFreeで必ず開放してあげてください。(と良く言われました)
でないとプログラムが終了だか電源きるまで確保されたままなので
パソコンがフリーズする原因となりかねません(受け売りでーす)

私もN88BASICで育った人間で、ABしかほぼ使えません。
使えるものを全て駆使してやりたいことが出来ればそれで良いと思いますよ。

色々突っ込みどころが満載な返答ですが、上から目線だとか文盲だとかは
重々承知しておりますので、苦笑いでスルーされますようお願い申し上げます。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2010年5月08日(土) 06:47 
>しかし、トモカズさんは大人ですね。。。これからも頑張ってください。
ガキで悪かったですねえ。。。

>私もN88BASICで育った人間で、ABしかほぼ使えません。
僕もN88-BASICで育った人間ですがね。

>色々突っ込みどころが満載な返答ですが、上から目線だとか文盲だとかは
>重々承知しておりますので、苦笑いでスルーされますようお願い申し上げます。
僕に石を投げておいて予防線を張るのはいかがなもんでしょ。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2010年5月08日(土) 10:29 
koboさん、返信ありがとうございます。

>実験的な事を繰り返して

ご推察の通りです。様々なアイデアを試しつつ試行錯誤を繰り返しています。
それらのアイデアのほとんどがボツになったりしておりますが・・
そんな訳で今回の(処理速度向上の)質問も的外れだったかもしれませんね。

>まず第一に多次元配列ではない方法でも実験をされてはいかがでしょうか。

そうですね。それも検討してみましたがまだ実験するに至っておりませんでした。
結構、X座標 Y座標を使用して配列を参照するケースが多いので、
P%(X,Y) を P%(X*8+Y) とした場合、X*8に処理コストがかかってしまうのでは無いかと却下しておりました。※今回のケースでは*8です。これだと機械語もビットシフトしてくれていればコストはさほど無さそうな気がしてきました。
これも、簡単なサンプルでベンチマークしてみる必要がありそうですね。

>HeapAllocでメモリを確保して、どこに書き込むかは人間側で計算し管理して
>書き込んでいきます。

ちょっと勉強してみます。

>また、数式を出来るだけ計算しておいてあげるのも一つだと思います。
>(x*2)*(x*3)のような式であれば、これを展開しておいたほうが速いかもしれません。

以下のコードを書いてみました。

*TEST01-04のサブルーチンがソレです。予め計算結果を配列に代入しておき、それを参照して累計だけを行うというものです。※今回のケースでは配列に入力されている数値は0~2だけなので・・・
残念ながらこれだと(計算をするよりも)配列を読みに行く時間の方がかかってしまっていました。
(koboさんの書かれている内容と異なった解釈をしているのかもしれません)

中々と難しいものです。
次回は1次元配列を試してみようかと思っております。ご丁寧な解説をありがとうございました。

コード:
#N88BASIC

	Dim P%[9,9,59] AS Integer
	Dim R%[9,9,59] AS Char
	Dim Q%[59,9,9] AS Integer	'追加
	Dim TA1%	 AS Integer
	Dim X		 AS Char
	Dim Y		 AS Char
	Dim I$ AS STRING
	Dim dwStart AS int64
	Dim dwEnd AS int64
	Dim TIMECOUNT AS int64
	Dim CT AS Int64
	Dim CT2 AS Int64
	Dim N AS Char
	dim CV1[2]	 AS Integer 	'追加
	dim CV2[2]	 AS Integer 	'追加
	dim CV3[2]	 AS Integer 	'追加
	dim CV4[2]	 AS Integer 	'追加
	dim CV5[2]	 AS Integer 	'追加
	dim CV6[2]	 AS Integer 	'追加
	dim CV7[2]	 AS Integer 	'追加
	dim CV8[2]	 AS Integer 	'追加


'予め計算しておく				'追加
	FOR N=0 TO 2
		CV1[N]=N	
		CV2[N]=N*3	
		CV3[N]=N*3^2
		CV4[N]=N*3^3
		CV5[N]=N*3^4
		CV6[N]=N*3^5
		CV7[N]=N*3^6
		CV8[N]=N*3^7
	NEXT

	N=1	
	Randomize

	FOR X=1 TO 8
		FOR Y=1 TO 8
			P%[X,Y,N]=Int(Rnd()*3)
			Q%[N,X,Y]=P%[X,Y,N]
			R%[X,Y,N]=P%[X,Y,N] AS Char
		NEXT
	NEXT

	PRINT "計算スピードテスト"
    CT2=20000000

	Print 
	Gosub *TEST01-00:PRINT TA1%
	Gosub *TEST01-01:PRINT TA1%		'追加
	Gosub *TEST01-02:PRINT TA1%
	Gosub *TEST01-03:PRINT TA1%		'追加
	Gosub *TEST01-04:PRINT TA1%		'追加


	Print "Integer(通常)"
	dwStart = GetTickCount()
	FOR CT=0 TO CT2:GOSUB *TEST01-00:NEXT
	PRINT TA1%
	GOSUB *TIMEPRINT
	PRINT

	Print "Integer(通常) 配列順序を入れ替え"
	dwStart = GetTickCount()
	FOR CT=0 TO CT2:GOSUB *TEST01-01:NEXT
	PRINT TA1%
	GOSUB *TIMEPRINT
	PRINT

	Print "Char(Integerへ全部変換しながら計算)"
	dwStart = GetTickCount()
	FOR CT=0 TO CT2:GOSUB *TEST01-02:NEXT
	PRINT TA1%
	GOSUB *TIMEPRINT
	PRINT

	Print "Char(Integerへ一部変換しながら計算)"
	dwStart = GetTickCount()
	FOR CT=0 TO CT2:GOSUB *TEST01-03:NEXT
	PRINT TA1%
	GOSUB *TIMEPRINT
	PRINT

	Print "Char(Integerへ配列を参照して累計のみ 掛算なし)"
	dwStart = GetTickCount()
	FOR CT=0 TO CT2:GOSUB *TEST01-04:NEXT
	PRINT TA1%
	GOSUB *TIMEPRINT
	PRINT


	I$=Input$(1)
	END

*TIMEPRINT
	dwEnd = GetTickCount()
	TIMECOUNT=(dwEnd-dwStart)/100 
	PRINT TIMECOUNT/10;"秒" 
	RETURN

*TEST01-00
	TA1%=P%[1,1,N]+P%[1,2,N]*3+P%[1,3,N]*9+P%[1,4,N]*27+P%[1,5,N]*81+P%[1,6,N]*243+P%[1,7,N]*729+P%[1,8,N]*2187
	RETURN

*TEST01-01
	TA1%=Q%[N,1,1]+Q%[N,1,2]*3+Q%[N,1,3]*9+Q%[N,1,4]*27+Q%[N,1,5]*81+Q%[N,1,6]*243+Q%[N,1,7]*729+Q%[N,1,8]*2187
	RETURN

*TEST01-02
	TA1%=R%[1,1,N] AS Integer+R%[1,2,N] AS Integer*3+R%[1,3,N] AS Integer*9+R%[1,4,N] AS Integer*27+R%[1,5,N] AS Integer*81+R%[1,6,N] AS Integer*243+R%[1,7,N] AS Integer*729+R%[1,8,N] AS Integer*2187
	RETURN

*TEST01-03
	TA1%=(R%[1,1,N]+R%[1,2,N]*3+R%[1,3,N]*9+R%[1,4,N]*27) AS Integer +R%[1,5,N] AS Integer*81 +R%[1,6,N] AS Integer*243+R%[1,7,N] AS Integer*729+R%[1,8,N] AS Integer*2187
	RETURN

*TEST01-04
	TA1%=CV1[R%(1,1,N)]+CV2[R%(1,2,N)]+CV3[R%(1,3,N)]+CV4[R%(1,4,N)]+CV5[R%(1,5,N)]+CV6[R%(1,6,N)]+CV7[R%(1,7,N)]+CV8[R%(1,8,N)]
	RETURN


通報する
ページトップ
   
投稿記事Posted: 2010年5月10日(月) 18:14 
こんにちは。
やってみると中々勉強になりました。
トモカズさんのプログラムのしたいことに沿えているか疑問なのですが
書いてみました。
1、計算の基の数値は3まで
2、多次元配列だけど、計算で使うのは1本
3、各項に3の3倍数を順次掛けて足す
に注目だけしてみました。
でも、これがFunctionを使うと途端に遅くなるんですね・・・
FORの中に同じ式をほり込んでやるとぐっと早くなるのに。
計算コストとか処理のコストとかはさっぱり分からないですが
私の方ではこんなのを書いてみました。
下記ではFunctionは書いてありますが使っていません。
コード:
#N88BASIC

  Dim d as BytePtr

    Dim P%[9,9,59] AS Integer
    Dim R%[9,9,59] AS Byte
    Dim TA     AS DWord
    Dim X         AS Char
    Dim Y         AS Char
    Dim dwStart AS int64
    Dim dwEnd AS int64
    Dim TIMECOUNT AS int64
    Dim CT AS Int64
    Dim CT2 AS Int64
    Dim N AS Char

    N=1    

    Randomize

  d=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,9)

    FOR X=1 TO 8
        FOR Y=1 TO 8
            P%(X,Y,N)=Int(Rnd()*3)	
            R%(X,Y,N)=P%(X,Y,N) AS Char
        NEXT
    '使用する数値は3以下→1バイトでOKと思われる
    d[X-1]=P%(1,X,N)	'場所をずらして頂戴します。
    NEXT

    PRINT "計算スピードテスト"
    CT2=20000000

  Print "Byte"
    dwStart = GetTickCount()
    FOR CT=0 TO CT2
    'TA=TA + TEST_byte(d)
    TA=TA +d[0]+d[1]*3+d[2]*9+d[3]*27+d[4]*81+d[5]*243_
			+d[6]*729+d[7]*2187
  NEXT
    PRINT TA
    GOSUB *TIMEPRINT
  Sleep(-1)

    END

*TIMEPRINT
    dwEnd = GetTickCount()
    TIMECOUNT=(dwEnd-dwStart)/100 
    PRINT TIMECOUNT/10;"秒" 
    RETURN

Function TEST_byte(a as BytePtr) as Integer

 	TEST_byte=a[0]+a[1]*3+a[2]*9+a[3]*27+a[4]*81+a[5]*243_
			+a[6]*729+a[7]*2187

end Function
[/code]


通報する
ページトップ
   
期間内表示:  ソート  
新しいトピックを投稿する  トピックへ返信する  [ 8 件の記事 ] 

All times are UTC+09:00


オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[1人]


トピック投稿:  可
返信投稿:  可
記事編集: 不可
記事削除: 不可
ファイル添付: 不可

検索:
ページ移動:  
cron
Powered by phpBB® Forum Software © phpBB Limited
Japanese translation principally by KONISHI Yohsuke