欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C/C++高精度(加減乘除)算法中的壓位優(yōu)化

 更新時間:2023年01月31日 09:38:44   作者:CodeOfCC  
在高精度計算中數(shù)組的每個元素存儲一位10進(jìn)制的數(shù)字,這樣的存儲方式并不是最優(yōu)的,32位的整型其實至少可以存儲9位高精度數(shù)字,數(shù)組元素存儲更多的位數(shù)就是壓位優(yōu)化。本文將展示壓位優(yōu)化的原理以及壓9位的實現(xiàn)和性能對比,需要的可以參考一下

前言

由于上一章《C/C++ 高精度(加減乘除)算法簡單實現(xiàn)》實現(xiàn)了基本的高精度計算,數(shù)組的每個元素存儲一位10進(jìn)制的數(shù)字。這樣的存儲方式并不是最優(yōu)的,32位的整型其實至少可以存儲9位高精度數(shù)字,數(shù)組元素存儲更多的位數(shù)就是壓位優(yōu)化。本文將展示壓位優(yōu)化的原理以及壓9位的實現(xiàn)和性能對比。

一、基本原理

1、存儲方式

壓位優(yōu)化就是將原本存儲一位的數(shù)組元素變成存儲多位,這樣就可以提升運(yùn)算效率,通常最高能存儲9位,如下圖示例為存儲4位。

2、計算方式

采用模擬立豎式計算,比如加法的計算流程,如下圖所示,20481024+80001000=100482024:

二、完整代碼

因為接口以及使用方法與上一章《C/C++ 高精度(加減乘除)算法簡單實現(xiàn)》是完全一致的,所以這里直接展示完整代碼,省略使用示例。下面代碼為壓9位實現(xiàn)。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdint.h>
/// <summary>
/// 通過字符串初始化
/// </summary>
/// <param name="a">[in]高精度數(shù)組</param>
/// <param name="value">[in]字符串首地址</param>
static void loadStr(int* a, const char* value) {
	int len = strlen(value);
	int left = len % 9;
	char s[8], * p = (char*)value + left;
	a[0] = ceil(len / 9.0);
	len = len / 9.0;
	for (int i = 1; i <= len; i++)
		sscanf(p + (len - i ) * 9, "%09d", &a[i]);
	if (left){
		sprintf(s, "%%0%dd", left);
		sscanf(value, s, &a[a[0]]);
	}
}
/// <summary>
/// 輸出到字符串,
/// </summary>
/// <param name="a">[in]高精度數(shù)組</param>
/// <param name="str">[out]字符串,由外部停供緩沖區(qū),需要保證長度足夠</param>
static void toStr(int* a, char* str) {
	if (!a[0]) {
		sprintf(str, "0");
		return;
	}
	sprintf(str, "%d", a[a[0]]);
	str += strlen(str);
	for (int i = a[0]-1; i > 0; i--)
		sprintf(str +( a[0] -i-1)*9, "%09d", a[i]);
	str[(a[0]-1)*9] = '\0';
}
/// <summary>
/// 通過無符號整型初始化
/// </summary>
/// <param name="a">[in]高精度數(shù)組</param>
/// <param name="value">[in]整型值</param>
static void loadInt(int* a, uint64_t value) {
	a[0] = 0;
	while (value)a[++a[0]] = value % 1000000000, value /= 1000000000;
}

/// <summary>
/// 比較兩個高精度數(shù)的大小
/// </summary>
/// <param name="a">[in]第一個數(shù)</param>
/// <param name="b">[in]第二個數(shù)</param>
/// <returns>1是a>b,0是a==b,-1是a<b</returns>
static int compare(int* a, int* b) {
	if (a[0] > b[0])return 1;
	if (a[0] < b[0])return -1;
	for (int i = a[0]; i > 0; i--)
		if (a[i] > b[i])return 1;
		else if (a[i] < b[i])return -1;
	return 0;
}
/// <summary>
/// 復(fù)制
/// </summary>
/// <param name="a">[in]源</param>
/// <param name="b">[in]目標(biāo)</param>
static void copy(int* a, int* b) {
	memcpy(b, a, (a[0] + 1) * sizeof(int));
}
/// <summary>
/// 打印輸出結(jié)果
/// </summary>
static void print(int* a) {
	int i = a[0];
	printf("%d", a[i--]);
	for (; i > 0; i--)printf("%09d", a[i]);
}

/// <summary>
/// 加
/// </summary>
/// <param name="a">[in]被加數(shù)</param>
/// <param name="b">[in]加數(shù)</param>
/// <param name="c">[out]結(jié)果</param>
static	void plus(int* a, int* b, int* c) {
	int* p;
	if (a[0] < b[0])p = a, a = b, b = p;//確保a長度最大	
	int i = 1, alen = a[0], blen = b[0];
	c[0] = c[alen + 1] = 0;
	if (a != c)memcpy(c + blen + 1, a + blen + 1, (alen - blen) * sizeof(int));//a多出的部分直接拷貝到結(jié)果
	for (; i <= blen; i++) {
		c[i] = a[i] + b[i];
		if (c[i - 1] >= 1000000000)c[i - 1] -= 1000000000, c[i]++;//判斷上一位是否進(jìn)位	
	}
	i--;
	while (c[i++] >= 1000000000)c[i - 1] -= 1000000000, c[i]++;//繼續(xù)判斷進(jìn)位
	c[0] = c[alen + 1] ? alen + 1 : alen;//記錄長度
}
/// <summary>
/// 加等于
///結(jié)果會保存在a中
/// </summary>
/// <param name="a">[in]被加數(shù)</param>
/// <param name="b">[in]加數(shù)</param>
static	void plusq(int* a, int* b) {
	plus(a, b, a);
}

/// <summary>
/// 減
/// </summary>
/// <param name="a">[in]被減數(shù),被減數(shù)必須大于等于減數(shù)</param>
/// <param name="b">[in]減數(shù)</param>
/// <param name="c">[out]結(jié)果</param>
static	void sub(int* a, int* b, int* c) {
	int i = 1, alen = a[0];
	if (a != c)memcpy(c + b[0] + 1, a + b[0] + 1, (a[0] - b[0]) * sizeof(int));//a多出的部分直接拷貝到結(jié)果
	c[0] = 1;
	for (; i <= b[0]; i++) {
		c[i] = a[i] - b[i];
		if (c[i - 1] < 0)c[i - 1] += 1000000000, c[i] --;//判斷上一位是否補(bǔ)位		
	}
	i--;
	while (c[i++] < 0)c[i - 1] += 1000000000, c[i]--;//繼續(xù)判斷補(bǔ)位	
	while (!c[alen--]); c[0] = alen + 1;//記錄長度
}
/// <summary>
/// 減法等于
///結(jié)果會保存在a中
/// </summary>
/// <param name="a">[in]被減數(shù),被減數(shù)必須大于等于減數(shù)</param>
/// <param name="b">[in]減數(shù)</param>
static	void subq(int* a, int* b) {
	sub(a, b, a);
}

/// <summary>
/// 乘
/// </summary>
/// <param name="a">[in]被乘數(shù)</param>
/// <param name="b">[in]乘數(shù)</param>
/// <param name="c">[out]結(jié)果,數(shù)組長度必須大于等于aLen+bLen+1</param>
static	void mul(int* a, int* b, int c[]) {
	int len = a[0] + b[0], d = 0;
	memset(c, 0, sizeof(int) * (len + 1));
	b[b[0] + 1] = 0; c[0] = 1;//防止越界
	for (int i = 1; i <= a[0]; i++)
		for (int j = 1; j <= b[0] + 1; j++){
			int64_t t = (int64_t)a[i] * b[j] + c[j + i - 1] + d;
			c[j + i - 1] = t % 1000000000;
			d = t / 1000000000;
		}
	while (!c[len])len--; c[0] = len;
}
/// <summary>
/// 乘等于
/// 累乘,結(jié)果存放于a
/// </summary>
/// <param name="a">[in]被乘數(shù),數(shù)組長度必須大于等于2aLen+bLen+1</param>
/// <param name="b">[in]乘數(shù)</param>
static	void mulq(int* a, int* b) {
	int* c = a + a[0] + b[0] + 1;
	memcpy(c, a, (a[0] + 1) * sizeof(int));
	mul(c, b, a);
}

/// <summary>
/// 除法
/// 依賴減法subq
/// </summary>
/// <param name="a">[in]被除數(shù),被除數(shù)必須大于除數(shù)</param>
/// <param name="b">[in]除數(shù)</param>
/// <param name="c">[out]商,數(shù)組長度大于等于3aLen-bLen+1</param>
/// <param name="mod">[out]余數(shù),可以為NULL,數(shù)組長度大于等于aLen</param>>
static void div(int* a, int* b, int* c, int* mod) {
	int len = a[0] - b[0] + 1, times, hTimes[32], * temp = c + a[0] + 1;
	if (!mod)mod = temp + 2*(a[0] + 1)+1;//緩沖區(qū)
	memcpy(mod, a, (a[0] + 1) * sizeof(int));
	memset(c, 0, sizeof(int) * (len + 1));
	memset(temp, 0, sizeof(int) * len);
	c[0] = 1;//防止while越界
	for (int i = len; i > 0; i--) {
		memcpy(temp + i, b + 1, sizeof(int) * b[0]);//升階	
		temp[0] = b[0] + i - 1;
		while (compare(mod, temp) != -1) {
			if (times = (mod[mod[0]] * ((mod[0] - temp[0]) ? 1000000000ll : 1)) / (temp[temp[0]] + (temp[0] == 1 ? 0 : 1)))//升倍數(shù)
			{
				loadInt(hTimes,times);
				mulq(temp, hTimes);
			}
			else times = 1;
			while (compare(mod, temp) != -1)subq(mod, temp), c[i] += times;	//減法
			memcpy(temp + i, b + 1, sizeof(int) * b[0]);//還原	
			temp[0] = b[0] + i - 1;
		}
	}
	while (!c[len])len--; c[0] = len;
}
/// <summary>
/// 除等于
/// 商保存在a
/// 依賴div
/// </summary>
/// <param name="a">[in]被除數(shù),被除數(shù)必須大于除數(shù)</param>
/// <param name="b">[in]除數(shù)</param>
/// <param name="mod">[out]余數(shù),可以為NULL,數(shù)組長度大于等于aLen</param>>
static void divq(int* a, int* b, int* mod) {
	div(a, b, a, mod);
}

三、性能對比

測試平臺:Windows 11

測試設(shè)備:i7 8750h

測試方式:測試5次取均值

表1、測試用例

測試用例描述
1整型范圍數(shù)字計算500000次
2長數(shù)字與整型范圍數(shù)字計算500000次
3長數(shù)字與長數(shù)字計算500000次

基于上述用例編寫程序進(jìn)行測試,測試結(jié)果如下表

表2、測試結(jié)果

計算測試用例1位實現(xiàn)(上一章)耗時9位優(yōu)化(本章)耗時
加法測試用例10.003926s0.002620s
加法測試用例20.026735s0.005711s
加法測試用例30.029378s0.005384s
累加測試用例10.003255s0.002536s
累加測試用例20.017843s0.002592s
累加測試用例30.034025s0.006474s
減法測試用例10.004237s0.002078s
減法測試用例20.024775s0.004939s
減法測試用例30.027634s0.004929s
累減測試用例10.004272s0.002034s
累減測試用例20.0054070.001942s
累減測試用例30.019363s0.004282s
乘法測試用例10.043608s0.004751s
乘法測試用例20.479071s0.028358s
乘法測試用例33.375447s0.064259s
累乘測試用例1 只計算1000次0.001237s0.000137s
累乘測試用例2 只計算1000次0.001577s0.000187s
累乘測試用例3 只計算1000次5.792887s0.081988s
除法測試用例10.025391s0.024763s
除法測試用例25.292809s0.516090s
除法測試用例30.395773s0.073812s
累除測試用例1 只計算1000次0.059054s0.035722s
累除測試用例2 只計算1000次0.103727s0.060936s
累除測試用例3 只計算1000次89.748837s25.126072s

將上表數(shù)據(jù)進(jìn)行分類相同類型取均值計算出提升速度如下圖所示,僅作參考。

圖1、速度提升

總結(jié)

以上就是今天要講的內(nèi)容,壓位優(yōu)化性能提升是比較顯著的,而且實現(xiàn)也很容易,大部分邏輯是一致的只是底數(shù)變大了而已。從性能測試結(jié)果來看所有計算至少由4倍的提升,乘法性能提升較大有可能是測試方法不嚴(yán)重,這個待以后驗證。總的來說,對高精度運(yùn)算進(jìn)行壓位優(yōu)化還是很有必要的,尤其是對時間和空間有要求的場景還是比較適用的。

附錄 1、性能測試代碼

#include<Windows.h>
#include <iostream>
static int a[819200];
static int b[819200];
static int c[819200];
static int mod[819200];
static char str[81920];
/// <summary>
/// 返回當(dāng)前時間
/// </summary>
/// <returns>當(dāng)前時間,單位秒,精度微秒</returns>
static double  getCurrentTime()
{
	LARGE_INTEGER ticks, Frequency;
	QueryPerformanceFrequency(&Frequency);
	QueryPerformanceCounter(&ticks);
	return  (double)ticks.QuadPart / (double)Frequency.QuadPart;
}
/// <summary>
/// 性能測試
/// </summary>
static void test() {
	double d = getCurrentTime();
	loadStr(a, "50000");
	loadInt(b, 50000);
	for (int64_t i = 1; i <= 500000; i++) {
		plus(a, b, c);
	}
	printf("plus  performence   1: %llfs\n", getCurrentTime() - d);
	d = getCurrentTime();
	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadInt(b, 5);
	for (int64_t i = 1; i <= 500000; i++) {
		plus(a, b, c);
	}
	printf("plus  performence   2: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadStr(b, "11111111111111111111111111111111111111");
	for (int64_t i = 1; i <= 500000; i++) {
		plus(b, a, c);
	}
	printf("plus  performence   3: %llfs\n", getCurrentTime() - d);


	d = getCurrentTime();
	loadStr(a, "50000");
	loadInt(b, 50000);
	for (int64_t i = 1; i <= 500000; i++) {
		plusq(a, b);
	}
	printf("plusq performence   1: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	for (int64_t i = 500000000; i <= 500000000 + 500000; i++) {
		loadInt(b, i);
		plusq(a, b);
	}
	printf("plusq performence   2: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(b, "999999999999999999999999999999999999999999999999999999999999999999");
	for (int64_t i = 500000000; i <= 500000000 + 500000; i++) {
		loadInt(a, i);
		plusq(a, b);

	}
	printf("plusq performence   3: %llfs\n", getCurrentTime() - d);


	d = getCurrentTime();
	loadStr(a, "50000");
	loadInt(b, 10000);
	for (int64_t i = 1; i <= 500000; i++) {
		sub(a, b, c);
	}
	printf("sub   performence   1: %llfs\n", getCurrentTime() - d);



	d = getCurrentTime();
	loadStr(a, "100000000000000000000000000000000000000000000000000000000000000000");
	loadInt(b, 11111);
	for (int64_t i = 1; i <= 500000; i++) {
		sub(a, b, c);
	}
	printf("sub   performence   2: %llfs\n", getCurrentTime() - d);


	d = getCurrentTime();
	loadStr(a, "100000000000000000000000000000000000000000000000000000000000000000");
	loadStr(b, "11111111111111111111111111111111111111");
	for (int64_t i = 1; i <= 500000; i++) {
		sub(a, b, c);
	}
	printf("sub   performence   3: %llfs\n", getCurrentTime() - d);



	d = getCurrentTime();
	loadStr(a, "50000000000");
	loadInt(b, 500000);
	for (int64_t i = 1; i <= 500000; i++) {
		subq(a, b);
	}
	printf("subq  performence   1: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "100000000000000000000000000000000000000000000000000000000000000000");
	loadInt(b, 11111);
	for (int64_t i = 1; i <= 500000; i++) {
		subq(a, b);
	}
	printf("subq  performence   2: %llfs\n", getCurrentTime() - d);


	
	d = getCurrentTime();
	loadStr(a, "100000000000000000000000000000000000000000000000000000000000000000");
	loadStr(b, "11111111111111111111111111111111111111");
	for (int64_t i = 1; i <= 500000; i++) {
		subq(a, b);
	}
	printf("subq  performence   3: %llfs\n", getCurrentTime() - d);


	d = getCurrentTime();
	loadStr(a, "50000");
	loadInt(b, 12345);
	for (int64_t i = 1; i <= 500000; i++) {
		mul(a, b, c);
	}
	printf("mul   performence   1: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadInt(b, 12345);
	for (int64_t i = 1; i <= 500000; i++) {
		mul(a, b, c);
	}
	printf("mul   performence   2: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadStr(b, "11111111111111111111111111111111111111");
	for (int64_t i = 1; i <= 500000; i++) {
		mul(b, a, c);
	}
	printf("mul   performence   3: %llfs\n", getCurrentTime() - d);


	d = getCurrentTime();
	loadStr(a, "2");
	loadInt(b, 2);
	for (int64_t i = 1; i <= 1000; i++) {
		mulq(a, b);
	}
	printf("mulq  performence   1: %llfs\n", getCurrentTime() - d);
	d = getCurrentTime();
	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadInt(b, 2);
	for (int64_t i = 1; i <= 1000; i++) {
		mulq(a, b);
	}
	printf("mulq  performence   2: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadStr(b, "11111111111111111111111111111111111111");
	for (int64_t i = 1; i <= 1000; i++) {
		mulq(b, a);
	}
	printf("mulq  performence   3: %llfs\n", getCurrentTime() - d);



	d = getCurrentTime();
	loadStr(a, "50000");
	loadInt(b, 12345);
	for (int64_t i = 1; i <= 500000; i++) {
		div(a, b, c, mod);
	}
	printf("div   performence   1: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "100000000000000000000000000000000000000000000000000000000000000000");
	loadInt(b, 12345);
	for (int64_t i = 1; i <= 500000; i++) {
		div(a, b, c, NULL);
	}
	printf("div   performence   2: %llfs\n", getCurrentTime() - d);

	d = getCurrentTime();
	loadStr(a, "100000000000000000000000000000000000000000000000000000000000000000");
	loadStr(b, "11111111111111111111111111111111111111");
	for (int64_t i = 1; i <= 500000; i++) {
		div(a, b, c, mod);
	}
	printf("div   performence   3: %llfs\n", getCurrentTime() - d);



	loadStr(a, "1");
	loadStr(b, "2");
	for (int64_t i = 1; i <= 1000; i++) {
		mulq(a, b);
	}
	d = getCurrentTime();
	for (int64_t i = 1; i <= 1000; i++) {
		divq(a, b, mod);
	}
	printf("divq  performence   1: %llfs\n", getCurrentTime() - d);

	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadStr(b, "2");
	for (int64_t i = 1; i <= 1000; i++) {
		mulq(a, b);
	}
	d = getCurrentTime();
	for (int64_t i = 1; i <= 1000; i++) {
		divq(a, b, mod);
	}
	printf("divq  performence   2: %llfs\n", getCurrentTime() - d);



	loadStr(a, "999999999999999999999999999999999999999999999999999999999999999999");
	loadStr(b, "11111111111111111111111111111111111111");
	for (int64_t i = 1; i <= 500; i++) {
		mulq(a, b);
	}
	d = getCurrentTime();
	for (int64_t i = 1; i <= 500; i++) {
		divq(a, b, mod);
	}
	printf("divq  performence   3: %llfs\n", getCurrentTime() - d);
}

到此這篇關(guān)于詳解C/C++高精度(加減乘除)算法中的壓位優(yōu)化的文章就介紹到這了,更多相關(guān)C++壓位優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實現(xiàn)一個通訊錄

    C語言實現(xiàn)一個通訊錄

    這篇文章主要為大家詳細(xì)介紹了用C語言實現(xiàn)一個通訊錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 詳解PID控制器原理

    詳解PID控制器原理

    什么是 PID?它是一種在編程中使用的基本方法,如果正確調(diào)整,可以令人難以置信的有效和準(zhǔn)確,PID代表比例積分微分,3個單獨(dú)的部分連接在一起,雖然有時你不需要三個都使用。例如,您可以改為有P控制,PI控制或PD控制
    2021-06-06
  • 深入了解C++中map用法

    深入了解C++中map用法

    下面小編就為大家?guī)硪黄钊肓私釩++中map用法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨想過來看看吧
    2016-06-06
  • C語言實現(xiàn)手寫紅黑樹的示例代碼

    C語言實現(xiàn)手寫紅黑樹的示例代碼

    紅黑樹在表意上就是一棵每個節(jié)點(diǎn)帶有顏色的二叉搜索樹,并通過對節(jié)點(diǎn)顏色的控制,使該二叉搜索樹達(dá)到盡量平衡的狀態(tài)。本文主將用C語言實現(xiàn)手寫紅黑樹,需要的可以參考一下
    2022-09-09
  • C++實現(xiàn)線性表順序存儲的示例代碼

    C++實現(xiàn)線性表順序存儲的示例代碼

    這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)線性表順序存儲的相關(guān)知識,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的可以了解一下
    2023-03-03
  • C語言入門篇--初識結(jié)構(gòu)體

    C語言入門篇--初識結(jié)構(gòu)體

    本篇文章是基礎(chǔ)篇,適合c語言剛?cè)腴T的朋友,本文對c語言的結(jié)構(gòu)體做了簡單的分析,幫助大家快速入門c語言的世界,更好的理解c語言
    2021-08-08
  • c++?error:crosses?initialization?of問題解決分析

    c++?error:crosses?initialization?of問題解決分析

    這篇文章主要介紹了c++?error:crosses?initialization?ofde?問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • C++  boost 時間與日期處理詳細(xì)介紹

    C++ boost 時間與日期處理詳細(xì)介紹

    這篇文章主要介紹了C++ boost 時間與日期處理詳細(xì)介紹的相關(guān)資料,這里提供實例代碼,及實現(xiàn)效果,需要的朋友可以參考下
    2016-11-11
  • C++超詳細(xì)講解模板的使用

    C++超詳細(xì)講解模板的使用

    這篇文章主要介紹了C++中模板(Template)的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • 關(guān)于C語言一維數(shù)組算法問題詳解

    關(guān)于C語言一維數(shù)組算法問題詳解

    數(shù)組是以順序格式排列的均勻數(shù)據(jù)的集合,在C語言中學(xué)習(xí)數(shù)組的概念非常重要,因為它是基本的數(shù)據(jù)結(jié)構(gòu),這篇文章主要給大家介紹了關(guān)于C語言一維數(shù)組算法問題的相關(guān)資料,需要的朋友可以參考下
    2021-11-11

最新評論