討論
在上一篇部落格『如何使用PHP最高效率的將一個正整數擴大一千倍?』的討論區,有人提出位移符應該才是運算最快的方案。
以前總是看到位移符<<
這樣的符號。因為它總是能輕易把一個數字變成我不認識的模樣,所以我也沒有深入瞭解過。
在看到討論區留言後才意識到:自己的格局太小了。
簡單讀了讀位移符
的文件和實現原理,我覺得這種方案還是值得一試的。按照之前兩篇部落格的心得,我首先丟擲我的猜測:
在
PHP
中,位移符方案效率要高於*1024
,但是會低於*1000
。在
GO
中,位移符的效率與其他兩種方案持平。
現在進行一個簡單的驗證。
方案一:$integer * 1000
方案二:($integer << 10) - ($integer * 24)
方案三:($integer * 1024) - ($integer * 24)
PHP
程式碼部分
這次吸取討論區提到的“效率權重”,將隨機數部分轉移出來。程式碼價值較低,為不影響閱讀,置於附錄
運算結果
多次執行並且調整前後順序,均得到一個較為穩定的結果:
這個結果在意料之中,但又不完全在。位移符<<
從理論上來講和一般的乘法有著本質上的不同,應該有不錯的效率提升。它之所以會比$integer * 1000
效率低,應該是被第二步運算- $integer * 24
拖累了,但是位移符
卻也沒有與*1024
拉開差距。為了證實這一點,我又補上了單獨進行位移計算的測試。結果證明:
位移符在
PHP
這裡就僅僅是一個普通的乘除法計算而已。
GO
程式碼部分
程式碼價值較低,為不影響閱讀,置於附錄
運算結果
執行結果同樣不出所料。
不過橫向對比一下,PHP
的計算效率被GO
秒的渣渣都不剩了。身為一名從PHP
入行程式設計,並且現在的主要技術棧和生產能力依舊在PHP
身上的我,不免產生一種好可憐啊
的悲涼。
位移符可以幫助我們理解計算機的原理,但是在
GO
這類編譯型語言這裡,編譯器已經幫你完成了位移符能完成的計算。
附錄
PHP程式碼
<?php
namespace App\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
class DemoCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'demo:test';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
// 圖表內容
$headers = ['次數', '方案1:乘1000', '方案2:移位符', '方案3:乘以 1024', '補充測試:僅位移'];
$data = [
[0 => '第一次'],
[0 => '第二次'],
[0 => '第三次']
];
// 隨機數提出
$integer = rand(1, 999);
// 每個方法執行三次
for ($count = 0; $count < 3; $count++) {
$start = Carbon::now()->getPreciseTimestamp();
for ($i = 0; $i < 10000000; $i++) {
$result = $integer * 1000;
}
$end = Carbon::now()->getPreciseTimestamp();
$data[$count][] = ($end - $start) / 1000000 . '秒';
}
for ($count = 0; $count < 3; $count++) {
$start = Carbon::now()->getPreciseTimestamp();
for ($i = 0; $i < 10000000; $i++) {
$result = ($integer << 10) - ($integer * 24);
}
$end = Carbon::now()->getPreciseTimestamp();
$data[$count][] = ($end - $start) / 1000000 . '秒';
}
for ($count = 0; $count < 3; $count++) {
$start = Carbon::now()->getPreciseTimestamp();
for ($i = 0; $i < 10000000; $i++) {
$result = ($integer * 1024) - ($integer * 24);
}
$end = Carbon::now()->getPreciseTimestamp();
$data[$count][] = ($end - $start) / 1000000 . '秒';
}
for ($count = 0; $count < 3; $count++) {
$start = Carbon::now()->getPreciseTimestamp();
for ($i = 0; $i < 10000000; $i++) {
$result = $integer << 10;
}
$end = Carbon::now()->getPreciseTimestamp();
$data[$count][] = ($end - $start) / 1000000 . '秒';
}
$this->table($headers, $data);
}
}
GO程式碼
func main() {
// 計算次數
maxI := 10000000
rand.Seed(time.Now().UnixNano())
integer := rand.Intn(999)
echoString := ""
fmt.Println("方案1:乘1000")
for count := 0; count < 3; count++ {
// 開始
start := time.Now()
echoString += "第" + strconv.Itoa(count+1) + "次:"
for i := 0; i < maxI; i++ {
_ = integer * 1000
}
// 結束
end := time.Now()
betweenTime := float64(end.Sub(start).Nanoseconds()) / 1000000000
echoString += strconv.FormatFloat(betweenTime, 'f', 10, 64) + "秒"
}
fmt.Println(echoString)
echoString = ""
fmt.Println("方案2:位移符")
for count := 0; count < 3; count++ {
// 開始
start := time.Now()
echoString += "第" + strconv.Itoa(count+1) + "次:"
for i := 0; i < maxI; i++ {
_ = (integer << 10) - (integer * 24)
}
// 結束
end := time.Now()
betweenTime := float64(end.Sub(start).Nanoseconds()) / 1000000000
echoString += strconv.FormatFloat(betweenTime, 'f', 10, 64) + "秒"
}
fmt.Println(echoString)
echoString = ""
fmt.Println("方案3:乘以1024")
for count := 0; count < 3; count++ {
// 開始
start := time.Now()
echoString += "第" + strconv.Itoa(count+1) + "次:"
for i := 0; i < maxI; i++ {
_ = (integer * 1024) - (integer * 24)
}
// 結束
end := time.Now()
betweenTime := float64(end.Sub(start).Nanoseconds()) / 1000000000
echoString += strconv.FormatFloat(betweenTime, 'f', 10, 64) + "秒"
}
fmt.Println(echoString)
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結