我试图了解如何在下面的帖子中实现时间复杂度为O(1)的电源操作。
http://programmingpraxis.com/2015/03/03/three-powering-algorithms/2/
算法:
常量时间函数使用对数,并且受制于 浮点错误:
(定义(pow-constant b e)
(exp(*(log b)e)))> (追踪粉末常数)
(POW常数)
> (pow-constant 2 16)
|(pow-constant 2 16)
| 65535.99999999998
65535.99999999998
任何人都可以解释为什么这个算法有效吗? 为什么它是O(1)?
答案 0 :(得分:2)
我是Programming Praxis的作者。谢谢阅读!当然,您可以在Stack Overflow上提问,但也欢迎您在Programming Praxis的评论部分提问。回答你的问题:
首先,它起作用,因为这是对数的数学定义。要乘以两个数,取对数,将对数加在一起,然后取对数的反对数;在编程术语中: x × y = exp(log( x )+ log( y ))。供电操作取基数的对数,将对数乘以指数,然后取产品的反对数;在编程方面, x y = exp(log( x )× y )。
其次,只有你作弊才是O(1)。只有一个(常量)操作涉及指数,因此操作只是相对于指数的常数时间。但算术需要时间,实际上 n -bit数字的算术需要时间log( n ),但我们忽略了这一点。实际上,计算机只提供一些小的限制,对于单精度浮点数通常为3.4×10 38 ,对于双精度浮点数通常为1.8×10 308 彩车。在该范围内,内部使用的函数足够接近恒定时间,我们说采用对数和指数是O(1)。如果你使用像GMP那样的大十进制库,浮点数要大很多,那么说算术是在恒定时间内完成的。所以我想这取决于你想要的精确程度。
答案 1 :(得分:1)
工作原理:
A = exp(ln(A))
和ln (A^B) = B * ln(A)
,A^B
(与A中的A一样)等于exp(ln(A^B))
exp(B * ln(A))
;重写使用scheme / lisp的前缀表示法产生显示的函数。如果内存服务,这是使用相同的技术幻灯片规则(虽然他们也利用ln(a*b) = ln(a)+ln(b)
,其想法是添加比乘法更容易,但我对幻灯片规则的曝光仅限于古怪的高中物理老师和一位加密老师用它来解释大数学的某些技巧。
为什么是O(1):
我不同意声称对于任意大小的数字,这是O(1)。这已经太久了,因为我已经看过O复杂性对于大数对数/取幂,但我很确定它们不是O(1)关于数字的大小,但另一方面,这些是无损数学。对于约束到浮点数大小的数字,这些操作是O(1)的相当好的近似值,但是你会失去精度。