一年一度的高考揭榜了,小H邻居家的孩子S考得不错,有望考上T大。
小H在楼下见到S和他的妈妈,S的妈妈对S说:你看,你还记得小H当初教你背圆周率吗?
S想起来了,小时候小H对他说:你去背圆周率,背到100位就给你买雪糕吃!
但是,直到S考上大学,小H还是没有给S买过雪糕。
“那么,等我读了大学,是不是就能学会,圆周率是怎么算出来的呢?”
小H陷入了沉思。
画面一转,历史的车轮从西晋时期开始转动。
一位穿着道袍的中年人在地上绘制着图形。他绘制的是一个一丈大的圆形,原型内部有一个个重叠的多边形。
随着多边形边数的增加,多边形也越来越接近圆形。
这是西晋著名数学家刘徽在使用“割圆术”来计算圆周率。在《九章算术注》中,刘徽给出了通过3072边形,逼近圆形,计算出的圆周率值3.1416。
与此几乎同一时代的古希腊和古罗马,为了计算圆周率,使用的方法是,在圆周上放一圈米粒,再往圆的直径上放满米粒,对米粒数量做比较,得到圆周率。
小H看到这里,笑喷了。
方老师告诉小H,古代人使用这种方式计算圆周率,其根本原因是,圆周率是一个超越数(不能基于整数,用有限次加减乘除及幂运算得到的数),而对圆周率的计算,属于对超越函数(也就是不能通过有限个幂函数的和进行计算的函数)进行数值计算。
如:
Pi = arcsin(1) * 4
那么,在GPU中,会如何计算这样的一个函数呢?我们将问题进行延伸,三角函数、双曲函数、指数和对数函数在GPU中会如何计算呢?
实际上,在GPU的主要使用场景中,如纹理贴图,就难免涉及到三角函数的批量计算。
CUDA提供了两类超越函数的计算方式。
一类是标准方式,如:
sin(x) —— 正弦函数;
cos(x) —— 余弦函数;
tan(x) —— 正切函数;
exp(x) —— 指数函数;
log(x) —— 对数函数;
asin(x) —— 反正弦函数;
acos(x) —— 反余弦函数;
sinh(x) —— 双曲正弦函数;
cosh(x) —— 双曲余弦函数;
tanh(x) —— 双曲正切函数;
其他的数学类函数过多,不在此一一列举。
这一类函数的实现,实际上就是利用函数的麦克劳林展开来计算,如:
任何一名学习过《高等数学》的读者,都可以花一点点时间来推导出这些级数,结合C语言基础,也可以写出使用CPU通过计算这些级数,得到这些超越函数计算结果的程序。
在CUDA中,实际上也是利用各类超越函数的麦克劳林展开式,来进行这些超越函数的数值计算的。
(我们再讲一点点和没关系的,实际上三角函数和双曲函数都是指数函数的变体,这可以从欧拉公式很容易地得到)
我们从复平面上看:
小H默默地记在小本子上:想学好计算机,首先要学好数学!
感兴趣的同学,也可以通过这种方式手工计算出三角函数的值。
当然,在实践中,我们没有人会手算这些函数的值,在没有计算器的情况下,我们会在数学手册中进行查表得到近似值。
在GPU中,也提供了这一类查表得到近似值的方法——