More ... | 編集履歴:差分記録開始以来の数式の文字列を計算するモジュール(一度逆ポーランド記法に変換)の変更箇所
+ * スクリーンショット + [[$$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))") + }}} |