[https://mp.weixin.qq.com/s/GCCEJWbNscJyf4K5nleOnA](https://mp.weixin.qq.com/s/GCCEJWbNscJyf4K5nleOnA)
早在数千年之前,巴比伦人就已经发明了乘法。而就在上个月,数学家们又对这一运算方式进行了优化,使它越来越完美。
3 月 18 日,**两位研究人员有可能发现**有史以来最快的**计算两个超大数的乘法运算方式。****这篇论文的诞生,也意味着数学界最基本的运算方式又有了更新更有效的运算过程,**有望破解了一个已经存在近半个世纪的数学问题。
法国国家科学研究中心数学家,这篇论文的共同作者之一 Joris van der Hoeven 说道,“大部分人都以为自己在学校里面学到的方法就是最好的方法,但是实际上在研究界,**有关乘法的计算方法领域一直是十分活跃的,而且不断有着新的突破和优化**。”


**图丨 有史以来最快大数相乘算法的两位发明人,上为法国国家科学研究中心的数学家 Joris van der Hoeven ,下为新南威尔士大学教授 David Harvey。在计算超大数时,下图中的传统计算方法会变得十分吃力(来源:École Polytechnique)**
许多数学计算领域的难题,从圆周率的计算到寻找最新的更大的素数等等,其运算复杂性最终都将由为基本的乘法的运算速度决定。Van der Hoeven 认为,**许多其他类型的问题理论上可以达到的最快的被解决的速度极限,最终也都将由乘法的运算速度决定。**
“物理学中也有一些十分重要的常量,比如光速就是决定许多其他物理现象的基本参数,”Van der Hoeven 说,“如果你想知道计算机解决各种数学问题的速度有多快,那么整数乘法的运算速度也将是回答这一问题的一个基本参数,描述计算机的许多种运算的速度都将会用到这个参数。”
大多数人所学乘法的运算方法都是以下这种方法。**将两个乘数排成两行,用下面的乘数中的每一位数字分别去乘以上面的乘数的每一位数字,然后将所有的相乘结果相加。**比如说,如果是两个两位数的乘法运算,你需要进行四次两个一位数的相乘,然后将这四个相乘的结果相加。
这个我们在小学就学过的乘法的算法,即**竖式计算乘法**的方法,在进行 n 位数之间的相乘时,需要进行大约 n 的平方次个位数的相乘,这里 n 是每个乘数的位数。所以,两个三位数的乘法需要进行 9 次个位数的相乘,而如果你要进行的是两个 100 位数的大数相乘,就需要 10,000 次个位数的相乘。
****
**图丨传统的竖式计算方法(来源:互联网)**
上面说到的竖式计算方法,其实更适用于位数少的数字之间的相乘。当我们需要进行数百万位数或数十亿位数的乘数之间的相乘时,竖式计算方法就显得无能为力了,例如计算圆周率或者寻找更大的质数。
**如果要将两个 10 亿位数的数字相乘,需要进行十亿的平方次个位数的相乘,****这个运算需要现代计算机花费大约 30 年的时间。**
在过去的数千年以来,人们都认为没有比竖式计算方法更快的乘法的算法了。
直到 1960 年,一位名叫 Anatoly Karatsuba 的 23 岁的俄罗斯数学家参加了由 20 世纪最伟大的数学家之一 Andrey Kolmogorov 领导的研讨会。当时,Kolmogorov 断言,没有一种方法可以以少于 n 的平方次个位数之间的相乘来完成两个 n 位数之间的相乘。但是 Karatsuba 认为有;然后仅仅经过了一周的探索,他就找到了这种方法。
**高能预警, Karatsuba 提出的算法思路如下 :**
计算25乘以63, **传统的算法**如下需要4次个位数之间的相乘以及几次加法,如下:

Karatsuba 算法需要3次个位数之间的相乘以及几次加法和减法,如下:


后者看似步骤比较多,但其优势在特大数相乘时就显现出来了,主要体现在节省个位数之间相乘的次数上:当乘数的位数很多时,可以重复进行 Karatsuba过程,将原来的乘数拆分成更小的部分。**所进行的拆分的次数越多,相比传统算法,你就节省了越多次个位数之间的相乘。**
例如,计算 2531 乘以1467,传统的算法需要进行 16 次个位数之间的相乘,如下:

而 Karatsuba 算法只需要进行 9 次个位数之间的相乘,如下:


**(来源:quanta)**
**由此也可以看出,Karatsuba 的算法的主要想法是分治算法,也就是将大数的乘数分解成更小的部分,并以一种新颖的方式重新组合这些部分,这种方式可以用少量的加法和减法来代替大量的乘法。Karatsuba 算法节省了时间,因为这一运算仅需 2 的 n 次方次个位数的相乘,而不是之前的 n 的平方次。**
**宾夕法尼亚州立大学数学家 Martin Fürer 说道:“另外,比起竖式计算方法,你可以在学校里提前一年学会这种方法,因为这种方法更容易,你可以在线性的时间内快速完成运算,这几乎和从右到往左阅读数字一样快”。Martin Fürer 在 2007 年也创造了当时世界上最快的乘法算法。**
**在处理大数乘法时,可以重复进行 Karatsuba 过程,将原始数字拆分为几乎与数字的位数一样多个部分。通过每一次拆分,你都可以将本需要许多许多次的乘法以需要的运算次数少的加法和减法来替代。**
**新南威尔士大学的数学家,同时也是这篇新论文的共同作者之一 David Harvey 说:“Karatsuba 算法可以把一些乘法变成加法,而对于计算机来说加法会更快。”**
**使用 Karatsuba 的方法,可以达到在 n 的 1.58 次方次个位数的乘法后,完成两个 n 位数的乘数之间的相乘。然后在 1971 年,Arnold Schönhage 和 Volker Strassen 发表了一种能够以 n×log n×log(log n)次个位数的相乘来完成大数相乘方法,其中 log n 是 n 的对数。而利用 Karatsuba 的方法进行两个 10 亿位数字之间的相乘时,则大约需要 165 万亿个额外的步骤。**
****
**(来源:此次论文)**
Schönhage 和 Strassen 的大数相乘的算法,**对****之后的大数相乘算法的发展产生了两个重要的长期影响。**
首先,它头一次在大数相乘领域将一种来自于信号处理技术领域的被称为\*\*快速傅立叶变换的方法引入了该领域。之后的每一次快速乘法算法都以这种方法为基础。
另外一个重要影响是,在同一篇论文中,Schönhage 和 Strassen 推测道,应该有一个比他们所发现的算法更快的算法——一种只需要 n×log n 次运算的方法,而且这种算法将会是最快的算法。他们的推测主要是基于一种预感,因为他们觉得大数乘法的最少的基本操作次数应该比 n×log n×log(log n)这个公式更优雅。
“这其实是一种很普遍的共识,人们都认为既然乘法是一个如此重要的基本操作,**那么从美学的角度来看,这样一个重要的操作需要一个很优雅的复杂性极限的描述公式**,”Fürer 说,“**从普遍经验来看,最最基本的事物的数学描述总是十分优雅的**。”
不过,在之后的 36 年里,都没有人找到比 Schönhage 和 Strassen 这个不那么优雅的需要 n×log n×log(log n)次基本运算的算法更快的大数乘法的算法。

**(来源:quanta)**
直到 2007 年,Fürer 终于打破了这一领域一直没有进展的状态,而这次发现仿佛打开了人类这在一领域发现的阀门一般。在过去的十年中,数学家们不断的相继发现更快的乘法算法,而且每种算法都比之前更接近 n×log n,但是却一直没有完全达到它。**直到上个月,Harvey 和 van der Hoeven 终于达到了。**
他们的方法是对之前的主要方法的一种改进和优化。**他们的方法也会分割数字,使用快速傅立叶变换的改进版本,而且他们还利用了过去四十年间这一领域其他进步的成果**。van der Hoeven 说,“只不过我们以更激进的方式来使用快速傅里叶变换,我们的方法要进行多次快速傅里叶变换而不只是一次,而且也用加法和减法代替更多的乘法。”
Harvey 和 van der Hoeven 的算法证明了乘法可以进行 n×log n 次基本乘法来完成。但是,他们并不能证明没有比这种方法更快的算法。要证明这种方法是最好的方法要比发现这一算法困难得多。2 月底,奥胡斯大学的一个计算机科学家小组发表了一篇论文,认为如果另一个未经证实的猜想成立的话,这一方法将可以被证实确实是乘法的最快的算法。
虽然这一新的算法理论上将有着重大意义,但实际上比起之前的算法,它其实并没有进行太大的变化,它只比已经在被我们使用的算法稍微好一些。
“使用这种算法,最好的情况下也只比之前的算法最快三倍,”van der Hoeven 说。“这并没有比之前快很多。”
此外,计算机硬件的设计也在过去几年间发生了许多变化。二十年前,计算机执行加法要比乘法快很多。但是乘法和加法之间的运算速度的差距在过去 20 年中已经大大缩小,在某些芯片架构中,乘法甚至比加法更快。在使用某些硬件时,“你甚至可以让计算机通过做多次乘法来提高加法的运算速度,这在之前简直的不可想像的,”Harvey 说。
不过,**硬件随时间在不断发展,但是对于一种运算的最佳算法的寻找却是是永恒的没有尽头的。**无论计算机在未来会变成怎样,Harvey 和 van der Hoeven 的算法将一直会是最有效的乘法运算方法之一。
**图丨新算法的长图版(来源:quanta)**
**参考链接:**
*https://www.quantamagazine.org/mathematicians-discover-the-perfect-way-to-multiply-20190411/ *
*https://hal.archives-ouvertes.fr/hal-02070778/document*
- 程序优化
- vtune
- linux性能监控软件Perf
- 系统级性能分析工具perf的介绍与使用
- perf的二级命令
- 全局性概况
- 全局细节
- 最常用功能perf record
- 可视化工具perf timechart
- perf引入的overhead
- perf stat
- gprof
- 三种Linux性能分析工具的比较
- perf+gprof+gprof2dot+graphviz进行性能分析热点
- 英特尔多核平台编程优化大赛报告
- 内存操作
- mmap
- mmap的分类
- 深入理解内存映射mmap
- 计算机底层知识拾遗(九)深入理解内存映射mmap
- 内核驱动mmap Handler利用技术(一)
- Windows内存管理机制及C++内存分配实例
- Linux内存管理初探
- Windows CPU信息查看
- Linux CPU信息查看
- 预留大内存
- Linux下试验大页面映射
- /dev/mem
- Linux中通过/dev/mem操控物理地址
- /dev/mem分析
- 用法举例
- Linux下直接读写物理地址内存
- 查看内存信息
- Cache Memory
- 页面缓存
- 查看各级cache信息的方法
- dmidecode命令查看cache size
- CPU Cache 机制以及 Cache miss
- ARM体系关闭mmu和cache
- CR0-4寄存器介绍
- 查看CR0,CR2,CR3的值
- Linux 下如何禁用CPU cache
- 7个示例科普CPU Cache
- 第一个例子的C代码
- 其中之一
- Linux 从虚拟地址到物理地址
- 内存测试例子
- 每个程序员都应该了解的内存
- Part 1
- 程序员能够做什么
- 3 CPU caches
- 6 What Programmers Can Do
- VirtualAlloc
- Large-Page Support
- Some remarks on VirtualAlloc and MEM_LARGE_PAGES
- DMA
- MOV和MOVS的效率问题?如何高效的拷贝内存 中的数据
- how to use movntdqa to avoid cache pollution
- 计算机底层知识拾遗(一)理解虚拟内存机制
- How to access the control registers cr0,cr2,cr3 from a program
- 细说Cache-L1/L2/L3/TLB
- what-is-the-meaning-of-non-temporal-memory-accesses-in-x86
- How can the L1, L2, L3 CPU caches be turned off on modern x86/amd64 chips?
- UA list
- GDB
- 程序运行参数
- Linux下GDB的多线程调试
- CMake
- CMake快速入门教程:实战
- cmake打印变量值
- function
- source_group
- cmake_parse_arguments
- 编译.S文件
- add_definitions
- CMake添加-g编译选项
- Debug模式下启动
- Mysql
- Mysql联合查询union和union all的使用介绍
- MySQL数据库导入错误:ERROR 1064 (42000) 和 ERROR at line xx: Unknown command '\Z'.
- 解决MYSQL数据库 Table ‘xxx’ is marked as crashed and should be repaired 145错误
- C/C++
- c语言中static的作用
- strlen和sizeof有什么区别?
- printf
- Libuv中文文档之线程
- RapidJSON
- gcc/g++ 实战之编译的四个过程
- __thread
- TARGET_LINK_LIBRARIES
- MAP_HUGETLB
- 使用Intel格式的汇编
- __m128i
- emmintrin.h
- _mm_stream_si128
- _mm_stream_load_si128
- _mm_load_si128
- _mm_xor_si128
- _mm_store_si128
- _mm_cvtsi128_si64
- Intel SSE指令集
- _mm_set_epi64x
- _mm_aesenc_si128
- _umul128
- _mm_malloc
- reinterpret_cast
- strlen
- 读取UTF-8的txt文件发现开头的多三个字节的问题
- PHP
- php计算函数执行时间的方法
- 框架
- Json Rpc远程调用框架
- PHP多进程
- PHP CLI模式下的多进程应用
- php多进程总结
- 优化
- PHP7 优化
- 让你的PHP7更快(GCC PGO)
- PHP的性能演进(从PHP5.0到PHP7.1的性能全评测)
- PHP字符串全排列算法
- 获取服务器基本信息
- cookie
- phpstudy2018 安装xdebug扩展
- 软件下载
- PHP mysqli_error() 函数
- PHP Session 变量
- curl
- curl_getinfo
- 获取请求头
- PHP使用CURL获取302跳转后的地址实例
- PHP基于cURL实现自动模拟登录
- PHP获取远程图片大小(CURL实现)
- CURL模拟登录
- curl模拟登录提交(从目录中获取文件)
- CURL HTTPS
- curl帮v
- rename
- copy
- JSON
- json_encode
- json_decode
- json_last_error_msg
- json_last_error
- PHP json_encode中文乱码解决方法
- var_dump
- PHPStorm与Xdebug设置
- Xdebug原理以notepad为例
- str_pad
- pack
- PHP二进制与字符串之间的相互转换
- PHP执行系统命令(简介及方法)
- 函数
- 十进制转二进制
- 字符串到ASSCI
- 字符串转二进制
- 合并两个表
- 图像识别
- Tesseract
- 虚拟机
- vmware下Kali 2.0安装VMware Tools
- 安装 VMware tools出现“正在进行简易安装时,无法手动启动VMware tools安装”
- 爬虫
- 有哪些好的数据来源或者大数据平台?
- Cygwin
- Git 常用命令
- 排列组合
- 含重复元素序列的全排列
- 全排列的非递归和递归实现(含重复元素)
- GitBook
- 编辑环境
- visual studio code
- 2名数学家或发现史上最快超大乘法运算法,欲破解困扰人类近半个世纪的问题
- 系统预定义常量
- 指令集
- SSE
- _MSC_VER
- msys2
- 安装cmake
- MSYS2 更新源
- 讲Cmake msys32使用问题解答 CXX CMAKE_C_COMPILER配置详解
- VirtualBox
- 解决virtualbox只能安装32位系统的问题
- Ubuntu
- 使用AES-NI的编译参数
- debian下安装内核源码的方法
- tar.xz结尾的文件的解压方法
- Linux命令
- insmod
- fatal error: openssl/bio.h
- 准备module的编译环境(kali)
- Ubuntu/Debian 之内核模块开发准备
- dmesg的详细用法
- Linux系统开机自动加载驱动module
- linux /Module 浅析(转载)
- Kali
- 找回gpedit
- Enable the Lock Pages in Memory Option (Windows)
- TLA
- 双系统
- 显卡
- 显示no CUDA的解决过程
