位移符效率对比

讨论

在上一篇博客『如何使用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 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 2
sreio

来了,他终于来了[狗头] ,前几篇文章都有关注

2年前 评论
罐装仙人掌CuratorC (楼主) 2年前

:unamused: GO的基准测试它不香吗

2年前 评论
罐装仙人掌CuratorC (楼主) 2年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!