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

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

:::note
１．Windows 11 Pro
２．Visual Studio community 2022
３．「コンソールアプリ　C++　Windows　コンソール」として作成
:::
非推奨の```scnanf()```に警告が出てビルドできません。抑制するため、プロジェクトのプロパティを

![抑制4996.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/b5f4a9d7-94dc-4d2b-a5eb-6e22bbca9910.jpeg)

のようにしておきます。
　コードです。
```c: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();
	}
}
```
　これを「デバッグなしで開始」し、次のいくつかの例で確認してみました。数値とアルファベットを入力していきますが、各例では簡単のためリターンキーを「,」で代用して示します。

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

    16,5,r,3,5,3,^,*,r,-,*,4,239,/,-,
結果は「3.140597」で上記サイトと同じ。

-------------------------------------
例２．近似式
・(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」。直接計算と全く同じ。

--------------------------------------------
例３．対数計算
【参考】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」で上記サイトと同じ。

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

    1,2,!,r,+,3,!,r,+,4,!,r,+,5,!,r,+,6,!,r,+,
結果は「1.718056」でした。

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

    30,sid,45,cod,*,30,cod,45,sid,*,+,
結果は「0.965926」となり、直接計算したものと同じでした。

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