0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

71歳の... 逆ポーランド記法計算 Visual Studioでやってみた

Posted at

 スタック・スタックポインターの理解のため、逆ポーランド記法電卓をプログラミング、そして動作確認してみました。恥ずかしながら、逆ポーランド記法(ここでは後置法のつもり)を正確に理解しておりません(エヘヘ笑)。ご指摘お待ちします。環境は以下です。

1.Windows 11 Pro
2.Visual Studio community 2022
3.「コンソールアプリ C++ Windows コンソール」として作成

非推奨のscnanf()に警告が出てビルドできません。抑制するため、プロジェクトのプロパティを

抑制4996.jpg

のようにしておきます。
 コードです。

reversePolish.c
#define _USE_MATH_DEFINES
#define _CRT_SECURE_NO_WARNING
#include <stdio.h>
#include <math.h>
#include <corecrt_math_defines.h>

constexpr auto stMax = 50;
int sp = 0;
bool sp_err = true;;
double stack[stMax];

int strcmp(const char* a, const char* b) {
	while (*a == *b)
	{
		if (*a == '\0') return 0;
		a++; b++;
	}
	return (*a - *b);
}

void printStack() {
	printf("stack-----\n");
	for (int i = sp - 1; i >= 0; i--) 
		printf("No.%2d : %f\n", i, stack[i]);
	printf("----------\n");
}

int push(double n) {
	if (sp < stMax) {
		stack[sp++] = n;
		return 0;
	}
	else return -1;
}

int pop(double* n) {
	if (sp > 0) {
		*n = stack[--sp];
		return 0;
	}
	else {
		sp_err = false;
		printf("sp error. Under the Bottom.\n");
		return -1;
	}
}

double factorial(double n) {
	double ret = 1.0;
	for (double i = n; i > 0; i--) ret *= i;
	return ret;
}

int main() {
	while (sp_err) {
		char buf[20];
		printf(">");
		scanf("%s", buf);
		int sp_err = 0;

		if (*buf == 'q') {	break;// end
		}
		else if (*buf == 'a') { sp = 0; // All clear
		}
		else if (*buf == '+') {// input a, b, +
			double b, a;
			pop(&b); pop(&a);
			push(a + b);
		}
		else if (*buf == '-') {// input a, b, -
			double b, a;
			pop(&b); pop(&a);
			push(a - b);
		}
		else if (*buf == '*') {// input a, b, *
			double b, a;
			pop(&b); pop(&a);
			push(a * b);
		}
		else if (*buf == '/') {// input a, b, /
			double b, a;
			pop(&b);
			if (b == 0.0) {
				printf("devide by 0 error.\n"); break;
			}
			pop(&a);
			push(a / b);
		}
		else if (*buf == '^') {// power.  a^b
			double a, b;		// input a, b, ^
			pop(&b);pop(&a);
			push(pow(a, b));
		}
		else if (*buf == '!') {// factorial n! valid to 22! (23! invalid.)
			double a;			// input x, !
			pop(&a);
			push(factorial(a));
		}
		else if (*buf == 'r') { // reciprocal 1/x
			double a;			// input x, r
			pop(&a);
			push(1.0/a);
		}
		else if (strcmp(buf, "sr") == 0) {// square root
			double a;					// input x, sr
			pop(&a);
			push(sqrt(a));
		}
		else if (strcmp(buf, "nr") == 0) { // n-th root
			double a, b;				// input n, x, nr
			pop(&b);pop(&a);
			push(pow(b,1.0/a));
		}
		else if (strcmp(buf, "pi") == 0) { // Pi=3.141593
			push(M_PI);
		}
		else if (strcmp(buf, "ln") == 0) { // natural logarithm log(x)
			double a;					// input x, ln
			pop(&a);
			push(log(a));
		}
		else if (strcmp(buf, "log") == 0) {// log x (y)
			double a, b;				// input x, y, log
			pop(&b);pop(&a);
			push(log10(b) / log10(a));
		}
		else if (strcmp(buf, "exp") == 0) { // exp(x)
			double a;					// input x, exp
			pop(&a);
			push(exp(a));
		}
		else if (strcmp(buf, "sid") == 0) { // sin(x°)
			double DtoR = M_PI / 180.0;	// input x, sid
			double a;
			pop(&a);
			push(sin(a * DtoR));
		}
		else if (strcmp(buf, "cod") == 0) { // cos(x°)
			double DtoR = M_PI / 180.0;	// input x, cod
			double a;
			pop(&a);
			push(cos(a * DtoR));
		}
		else if (strcmp(buf, "tad") == 0) { // tan(x°)
			double DtoR = M_PI / 180.0;	// input x, tad
			double a;
			pop(&a);
			push(tan(a * DtoR));
		}
		else if (strcmp(buf, "sin") == 0) { // sin(x radian)
			double a;					// input x, sin
			pop(&a);
			push(sin(a));
		}
		else if (strcmp(buf, "cos") == 0) { // cos(x radian)
			double a;					// input x, cos
			pop(&a);
			push(cos(a));
		}
		else if (strcmp(buf, "tan") == 0) { // tan(x radian)
			double a;					// input x, tan
			pop(&a);
			push(tan(a));
		}
		else{
			/*
			for (int i = 0; i < strlen(buf); i++) {
				if (isdigit(buf[i])) {
					printf("%c is digit.\n", i, buf[i]);
				}
				else {
					printf("%c isn't digit.\n", i, buf[i]);
				}
			}
			*/
			double d = atof(buf);
			push(d);
		}
		printStack();
	}
}

 これを「デバッグなしで開始」し、次のいくつかの例で確認してみました。数値とアルファベットを入力していきますが、各例では簡単のためリターンキーを「,」で代用して示します。


例1.円周率を「マチンの公式」で計算
【参考】https://manabitimes.jp/math/1229
キー入力(「,」リターンキーのこと。以下同じ)

16,5,r,3,5,3,^,*,r,-,*,4,239,/,-,

結果は「3.140597」で上記サイトと同じ。


例2.近似式
・(1+x)^(1/2)≒1+(1/2)x-(1/8)x^2
【参考】https://rikeilabo.com/approximate-expression
キー入力(x=0.1)

1,0.1,2,/,+,0.1,2,^,8,/,-,

結果は「1.048750」で上記サイトと同じ。

・tan(x)≒x+(1/3)x^3+(1/5)x^5
【参考】https://www.takamasu-lab.org/wp-content/uploads/2023/11/prec-tip02.pdf
キー入力(x=0.1)

0.1,3,r,0.1,3,^,*,5,r,0.1,5,^,*,+,+,

結果は「0.100335」。直接計算と全く同じ。


例3.対数計算
【参考】https://www.optics-words.com/math/exp/exponentiation_6.html
【4-1】問題(1) 累乗根を含む対数
キー入力

3,4,48,nr,log,3,2,log,-,

結果は「0.25」で上記サイトと同じ。

【4-2】問題(2) 底の変換公式の問題
キー入力

9,5,log,1,2,/,1,3,/,5,log,*,+,

結果は「0.0」で上記サイトと同じ。

【4-4】問題(4) 対数を指数にもつ値
キー入力

10,10,8,log,^,

結果は「8.0」で上記サイトと同じ。


例4.階乗の逆数和 無限に加えるとネイピアの数e
無限に続けるわけにはいかないので途中まで
キー入力

1,2,!,r,+,3,!,r,+,4,!,r,+,5,!,r,+,6,!,r,+,

結果は「1.718056」でした。


例5.三角関数の加法定理の確認
 sin(30°+45°)=sin30°cos45°+cos30°sin45°
キー入力(右辺を入力)

30,sid,45,cod,*,30,cod,45,sid,*,+,

結果は「0.965926」となり、直接計算したものと同じでした。


 以上のキー入力が逆ポーランド記法(後置法)として正しいのか、わかってないのがお恥ずかしいですが、計算ができているようだということです。最後までお付き合いいただきありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?