位移符效率對比

罐裝仙人掌CuratorC發表於2021-04-29

討論

在上一篇部落格『如何使用PHP最高效率的將一個正整數擴大一千倍?』的討論區,有人提出位移符應該才是運算最快的方案。

以前總是看到位移符<<這樣的符號。因為它總是能輕易把一個數字變成我不認識的模樣,所以我也沒有深入瞭解過。

在看到討論區留言後才意識到:自己的格局太小了。

簡單讀了讀位移符的文件和實現原理,我覺得這種方案還是值得一試的。按照之前兩篇部落格的心得,我首先丟擲我的猜測:

現在進行一個簡單的驗證。

  • 方案一:$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 協議》,轉載必須註明作者和本文連結
忠誠,秩序,卓越,博愛,開拓

相關文章