[トップ][一覧][最近の更新]

編集履歴:差分

記録開始以来の数式の文字列を計算するモジュール(一度逆ポーランド記法に変換)の変更箇所

  • + 追加された行
  • - 削除された行

編集履歴ページに戻る

+ * スクリーンショット
+ [[$$img http://cdn.devlion.net/9c3ee9fa-44ab-11e5-9b58-5edc82371162.png]]
+ 
+ * calc.hsp
+ {{{
+ #module c
+ 	// 演算子の優先順序
+ 	// 低い
+ 	#enum UNKNOWN = -1
+ 	#enum PAREN   // 括弧は例外
+ 	#enum XOR_
+ 	#enum OR_
+ 	#enum AND_
+ 	#enum LESS
+ 	#enum GRTER
+ 	#enum EQUAL
+ 	#enum ADD
+ 	#enum SUB
+ 	#enum MULT
+ 	#enum DIV
+ 	#enum POW
+ 	// 高い
+ 
+ 	#define stack(%1,%2) sdim %1,20,%2:%1_i=0
+ 	#define push(%1,%2) %1(%1_i)=%2:%1_i++
+ 	#define ctype pop(%1) _pop@c(%1(%1_i-1),%1_i)
+ 	#defcfunc local _pop var val, var index
+ 		index--
+ 	return val
+ 	
+ 	#define logstack(%1) _tmp="%1:":repeat %1_i:_tmp+=%1(cnt)+",":loop:logmes _tmp
+ 
+ 	// 計算を行う
+ 	#defcfunc calc str f
+ 
+ 		// 逆ポーランド記法でスタックpriに計算式を積む
+ 		import f
+ 	
+ 		// 浮動小数点数で計算するかどうか
+ 		is_double = 0
+ 
+ 		repeat pri_i
+ 			token = pri(cnt)
+ 	
+ 			// 小数点が含まれていればそれ以降浮動小数点として扱う
+ 			is_double |= (instr(token, 1, ".") != -1)
+ 	
+ 			if ( to_ope(token) == UNKNOWN ) { // 数値なら
+ 				push sec, token
+ 			} else { // 演算子なら
+ 	
+ 				// 左辺、右辺を取得
+ 				right = pop(sec)
+ 				left  = pop(sec)
+ 	
+ 				// 文字列から変換
+ 				if (is_double) {
+ 					right = double(right)
+ 					left  = double(left)
+ 				} else {
+ 					right = int(right)
+ 					left  = int(left)
+ 				}
+ 	
+ 				// 計算処理
+ 				switch(to_ope(token))
+ 					case XOR_
+ 						push sec, str(int(left) ^ int(right))
+ 						swbreak
+ 					case OR_
+ 						push sec, str(int(left) | int(right))
+ 						swbreak
+ 					case AND_
+ 						push sec, str(int(left) & int(right))
+ 						swbreak
+ 					case LESS
+ 						push sec, str(left < right)
+ 						swbreak
+ 					case GRTER
+ 						push sec, str(left > right)
+ 						swbreak
+ 					case EQUAL
+ 						push sec, str(left == right)
+ 						swbreak
+ 					case ADD
+ 						push sec, str(left + right)
+ 						swbreak
+ 					case SUB
+ 						push sec, str(left - right)
+ 						swbreak
+ 					case MULT
+ 						push sec, str(left * right)
+ 						swbreak
+ 					case DIV
+ 						is_double = 1
+ 						push sec, str(double(left) / double(right))
+ 						swbreak
+ 					case POW
+ 						push sec, str(powf(left, right))
+ 						swbreak
+ 				swend
+ 			}
+ 		loop
+ 
+ 		if (is_double) {
+ 			return double(sec(0))
+ 		} else {
+ 			return int(sec(0))
+ 		}
+ 
+ 	return
+ 
+ 	#deffunc local import str f
+ 	
+ 		stack pri, 100
+ 		stack sec, 50
+ 	
+ 		target  = f
+ 	
+ 		val_tmp = ""
+ 	
+ 		is_val  = 0 // トークンが数値であるかどうか
+ 	
+ 		// 文字列の解析
+ 		repeat strlen(target)
+ 			token = strmid(target,cnt,1)
+ 
+ 			// 数字の場合
+ 			token_c = peek(token, 0)
+ 			if ('0' <= token_c && token_c <= '9' || token_c == '.') {
+ 				val_tmp += token // val_tmpに数値リテラルを作成する
+ 				
+ 				is_val = 1
+ 				continue
+ 			}
+ 	
+ 			// 数字と演算子の境で、val_tmpを積む
+ 			if (is_val) {
+ 				push pri, val_tmp
+ 				val_tmp = ""
+ 			}
+ 	
+ 			is_val = 0 // 演算子
+ 	
+ 			// 括弧は積むだけ
+ 			if (token == "(") {
+ 				push sec, token
+ 				continue
+ 			}
+ 	
+ 			// 対応する括弧までの演算子を移動する
+ 			if (token == ")") {
+ 				while(sec(sec_i-1) != "(")
+ 					push pri, pop(sec)
+ 				wend
+ 				sec_i--
+ 				continue
+ 			}
+ 	
+ 			// 演算子の優先順序の処理
+ 			if (sec_i > 0) {
+ 				if (to_ope(sec(sec_i-1)) > to_ope(token)) {
+ 					repeat sec_i
+ 						if (sec(sec_i-1) == "(") :break
+ 						push pri, pop(sec)
+ 					loop
+ 				}
+ 			}
+ 	
+ 			// 積む
+ 			push sec, token
+ 		loop
+ 	
+ 		// 数値リテラルが余っていれば積んどく
+ 		if (is_val) {
+ 			push pri, val_tmp
+ 		}
+ 	
+ 		// 残りの演算子を移動する
+ 		repeat sec_i
+ 			push pri, pop(sec)
+ 		loop
+ 
+ 	return
+ 
+ 	#defcfunc local to_ope str ope
+ 		// 演算子の判定
+ 		switch(ope)
+ 			case "~"
+ 				return XOR_
+ 			case "|"
+ 				return OR_
+ 			case "&"
+ 				return AND_
+ 			case "<"
+ 				return LESS
+ 			case ">"
+ 				return GRTER
+ 			case "="
+ 				return EQUAL
+ 			case "+"
+ 				return ADD
+ 			case "-"
+ 				return SUB
+ 			case "*"
+ 				return MULT
+ 			case "/"
+ 				return DIV
+ 			case "^"
+ 				return POW
+ 			case "("
+ 			case ")"
+ 				return PAREN
+ 				swbreak
+ 		swend
+ 	return UNKNOWN
+ 
+ #global
+ }}}
+ 
+ * sample.hsp
+ {{{
+ pi = calc("4*(1-1/3+1/5-1/7+1/9-1/11+1/13-1/15+1/17-1/19+1/21-1/23+1/25)")
+ mes "PI="+pi
+ 
+ mes
+ 
+ e = calc("1+1/1+1/(1*2)+1/(1*2*3)+1/(1*2*3*4)+1/(1*2*3*4)+1/(1*2*3*4*5)")
+ mes "E="+e
+ 
+ mes
+ 
+ cos1 = calc("1-1/(1*2)+1/(1*2*3*4)-1/(1*2*3*4*5*6)+1/(1*2*3*4*5*6*7*8)")
+ mes "COS(1)="+cos1
+ sin1 = calc("1-1/(1*2*3)+1/(1*2*3*4*5)-1/(1*2*3*4*5*6*7)+1/(1*2*3*4*5*6*7*8*9)")
+ mes "SIN(1)="+sin1
+ 
+ mes "COS^2(1)+SIN^2(1)="+calc(strf("%f^2+%f^2", cos1, sin1))
+ 
+ mes
+ mes "2^2^2^2="+calc("2^2^2^2")
+ 
+ mes
+ mes "(2^4=4^2)&(5^3<3^5)="+calc("(2^4=4^2)&(5^3<3^5)")
+ 
+ mes
+ mes "(1~(1&0))=((1~1)|(1~0))="+calc("(1~(1&0))=((1~1)|(1~0))")
+ }}}