【真心提问】VB乘方运算的实现方法
vb吧
全部回复
仅看楼主
level 15
最近在一个帖子里发表了“正整数次幂的乘方运算与多次乘法没有区别”这样的言论,立刻被大佬教育了,并且给出了有力的证据,让我认识到了自己的肤浅
现在我知道了,VB编译后的程序进行乘方运算时,首先要将运算数进行类型转换,然后再调用VB库中的“乘方函数”进行运算
但是,这位大佬并没有解释VB的乘方函数的算法原理,我想进一步追问,但是似乎问的方法不当,被大佬误解了,还对我进行了一番批评讽刺……泪目[泪]
所以我决定开一个提问帖,真心求解,希望这次不会有人误解我是倚仗等级大放厥词吧(其实大家应该也都明白,贴吧等级并不代表学问水平)
首先,根据我自己的理解,我知道乘方运算有两种算法:循环乘法和指数-对数运算,大致可以这样表示:
'计算x^n的算法
'循环乘法
y = 1
For i = 1 To n
y = y * x
Next i
'指数-对数运算
y = Exp(Log(x) * n)
现在,我的问题就是,VB乘方运算是否使用的是这两种算法?
希望大家回答,最好给出证据
2018年08月30日 06点08分 1
level 15
@涐吢铱舊囿儚 召唤那位大佬,并且在此真诚道歉,我对汇编一窍不通,所以连你讽刺教育我的话都看不懂,是在下才疏学浅,还望赐教
2018年08月30日 06点08分 2
谦虚啊,为一直把你当大佬,当我师傅,没想到你也有不解之处[真棒][滑稽]@初音✨七奈
2018年09月01日 15点09分
@小望3900 没有,我才不是什么大佬,每次我冒充大佬的时候,真正的大佬一定是这个表情:“关爱傻子的眼神”[滑稽]
2018年09月02日 07点09分
@初音✨七奈 哈哈哈
2018年09月02日 08点09分
@初音✨七奈 不过我觉得你已经很厉害了
2018年09月02日 08点09分
level 15
顺便问大家一个事情:
这位大佬提到了一句“谁都知道乘法运算和加法运算各有各自的运算单元”,我想知道这个吧里是不是都知道这个“常识”?如果是的话,我觉得我是时候退圈了……连这个都不知道还整天在这里误导新人,这算怎么回事啊,对吧?[滑稽]
2018年08月30日 07点08分 3
运算单元?我只知道乘法在CPU里是多次加法而已
2018年08月30日 07点08分
@马云爱逛京东 看来不是只有我一个人不知道这个常识
2018年08月30日 07点08分
@初音✨七奈 有不知道的知识很正常啊,学海无涯,回头是岸
2018年08月30日 07点08分
level 10
我只是觉得在VB层面上谈论这个问题太过遥远,有些东西看起来应该很简单,但VB背后说不定都“好心”帮你做了什么无用功,就连C语言,你指定了寄存器,它都不一定真按你指定寄存器存...
2018年08月30日 08点08分 4
如果你要说VB层面的话,乘方运算就是一个^符号的事,根本不需要关心什么算法;所以我问的显然不是VB层面的事情
2018年08月30日 08点08分
@初音✨七奈 然而没有接触VB基础库的机会,但是一般整数幂都是用的快速幂
2018年08月30日 08点08分
@冰之源___ 也就是说,类似于加法运算单元和乘法运算单元,乘方也有自己独立的运算单元?(好像有的CPU确实有乘方运算指令?)
2018年08月30日 09点08分
@初音✨七奈 CPU有乘法器的都不多,再来个乘方器岂不是要浪费大量空间。
2018年08月30日 09点08分
level 10
真不知道,怎么会有人认为“乘法”一定是用加法来实现呢……
虽然从数学上的角度来说,理论上它的“实质”确实如此,
  但理论与现实之间,并不是所有的东西都会一样啊。
多说无益,用一段简单的代码,就以“整数乘法运算”来测试,
 以“实测结果”来说吧……(代码在后面贴)
按你们的说法,如果“乘法”得由加法来实现,那么……
下面几个“运行耗时”,理论上说,假设调用ProcAdd()的耗时为“1个单位时间”,
那么调用ProcMulA()的耗时,岂不是要消耗“1万个单位时间”了?
然而实际上可以说是“相等”的。
 那么反过来说,它做乘法时,把运算速度提升了1万倍?
你觉得有这可能吗!
好吧,暂时放下这个“差异”不究,另比较一个耗时:
在ProcMulA()中,计算的是10000乘10000,肯定得“做1万次加法”;
而在ProcMulB()中,计算的是20000乘20000,那肯定得“做2万次加法”。
那么,调用ProcMulB()的耗时,应该是调用ProcMulA()的2位呀……
然而,实际测试结果是,这4个函数的耗时,可以说是“相同”的。
注意:GetTickCount()的时间精度大概是10到15ms,再加上系统其它因素影响,
因此这个“总耗时”不可能是精确的。排除“误差因素”,就是“时间相同”了。
这说明什么问题呢?
其实就是说明了:
当今的CPU,这些简单运算,做1次加法运算、跟做1次乘法运算,
 耗时是相同的!(整数加法和整数乘法,都是“1个指令周期”完成运算)
整数乘法,也不可能转换成“循环做加法”来实现!
这是我的电脑上某次运行结果的截图:
当然,不同的硬件环境,运行耗时也会不同的。
编译后运行,也会比在IDE中运行快得多(耗时明显减少)。
2018年08月30日 08点08分 5
输入错误一个字,纠正一下“那么,调用ProcMulB()的耗时,应该是调用ProcMulA()的2位呀” 正确的是“2倍”,不是“2位”。
2018年08月30日 08点08分
好的,感谢大佬费心解释我在3楼复述的“常识”,那么能否麻烦您回答一下我这个帖子的主要问题呢?
2018年08月30日 08点08分
这个测试,缺失,我记得我也做过。也深刻的推翻了我的原来的印象。
2021年01月06日 08点01分
level 10
楼主想知道“指数运算”如何实现的,可以看看msvbvm60.dll的反汇编代码。
导出函数是 __vbaPowerR8 。
反汇编后,它的函数入口地址是::72A211CA
高级语言写的代码,可能是找不到的,毕竟这些库函数源代码,一般不会公开。
不过楼主也可以尝试找一下c语言的库函数,看能否找到源码。
我反正是没有去深究个这个,毕竟没有什么现实意义。
不过我可以肯定的说,即使是整数次幂,
 不会是用循环乘法实现、也不会是用“指数-对数运算”实现。
幂运算的“指数”,它只会区别0/正数/负数,不会区分整数/浮点数。
2018年08月30日 08点08分 6
level 10
其实我还没有说完[滑稽]所以我只能想到两个方法,一个就是宏观法同一句代码从第二次开始运行多次看时间(第一次系统会打缓存),一个就是微观法看反汇编结果,但我不知道反汇编的方法。楼上那位大佬整好已经从这两个角度切入了
2018年08月30日 09点08分 7
level 15
嗯,大佬在6楼提出了观点:幂运算的“指数”,它只会区别0/正数/负数,不会区分整数/浮点数
那么真的是这样么?我还是举几个例子吧
在窗体上放两个按钮Command1和Command2,编写如下代码:
Private Sub Command1_Click()
Print (-3) ^ 3
End Sub
Private Sub Command2_Click()
Print (-3) ^ (1 / 3)
End Sub
如果指数真的不区分整数和浮点数的话,那么这两个按钮的运行情况应该没有区别才对,但是……
点击Command1,正常运行,窗体内部输出-27
点击Command2,程序报错了:“无效的过程调用或参数”
这说明什么?
其实,这就是我一开始提出两种算法的依据,因为VB的乘方运算的指数确实是区分整数和浮点数的,显然它们用的是两种不同的算法(虽然我不知道具体是什么算法,帖子当中提到的算法也只是猜测)
2018年08月30日 09点08分 8
@冰之源___ [喷][喷][喷]你好聪明啊,居然这样推论出“VB的double是二进制存的”……难道其它计算机语言的double就不是二进制存储的了???[狂汗]
2018年08月30日 09点08分
虽然手头没有VB的IDE,但是一般通用库除了C++可以模板元以外,都不会可以去区分整数和实数,整数一般用快速幂,实数一般用牛顿迭代.通用就一般用牛顿迭代了.
2018年08月30日 09点08分
@冰之源___ 感谢解答
2018年08月30日 09点08分
楼主得你举这个例子,能说明我的论述是错误的?[滑稽] 我就问你一句:从数学上来说,(-3) ^ (1 / 3)的值是多少呢? (附加说明:计算机的“浮点类型”数据只属于数学上的“实数”的子集,那么这些结果必须是“实数”才符合要求),若从“数学”上都没有相应的计算结果,难道这个函数不应该报错吗!!!
2018年08月30日 09点08分
level 10
刚查了下Java 1.8中pow函数的源码,发现调用的是原生层方法,没法接着看下去了,但发现了这样一段描述“如果基数和指数都是整数,那么最后的运算结果是精确的数学意义上的乘方(如果结果可以用double型存下的话)”,可以推测,当两个参数都是整数的时候,应该还是会用特殊的算法的,只是最后强转成为double型
2018年08月30日 10点08分 9
level 15
好吧,果然有瞎猜的时间还不如直接验证来得实在……
自己写了4组代码对计算3^10的速度进行了比较:
1.乘方
2.循环乘法
3.多次乘法(单个的多项乘法表达式)
4.指数-对数运算
结果:循环乘法最慢,多次乘法最快,乘方和指数-对数运算接近……
自己打自己的脸感觉好爽[滑稽]
所以就算乘方有不同的算法,区分的应该也不是指数,而是底数
于是又写了一个负底数的代码((-3)^10),验证结果:与循环乘法接近[滑稽]
好了,这样应该就全部解释清楚了
果然之前自己的猜测幼稚得离谱啊……深刻教训,lesson learned
2018年08月30日 10点08分 10
level 15
搞这么高深
2018年08月30日 22点08分 11
level 12
涨姿势了……原来加法和乘法速度都是一样的[委屈]
2018年08月31日 03点08分 12
你不会也认为乘法是“循环累加”完成计算的吧……[滑稽]
2018年08月31日 03点08分
回复 涐吢铱舊囿儚 :是啊[滑稽]除了循环累加我还想到一种,“循环乘法口诀”
2018年08月31日 05点08分
2018年08月31日 05点08分
@一块小板子 你们都以为CPU在进行运算的时候,都象小学生做数学题那样进行计算的啊……[滑稽]
2018年08月31日 05点08分
level 3
@初音✨七奈 大佬大佬在吗我需要你帮我[呵呵]
2018年09月26日 12点09分 13
level 11
不看不知道,一看吓一跳。看了大神们讨论的课题,我只感觉我啥都不知道。
我不知道在什么地方看到说,最早的数值运算是在cpu里,后来在主板是有一个“数学协处理器”(我记得配8086cpu的是8087)。说只要是数值运算,就转给协处理器进行。
2018年09月27日 14点09分 14
你恐怕是记错了吧!早期的CPU,整数运算都是CPU内的运算单元完成,浮点运算才是交给“浮点运算协处理器”去计算的。后来的CPU,已经把浮点运算部件集成到CPU内部(好像是从“奔腾”CPU开始的吧,其实我也没太在意这些),直接作为CPU“管辖”的运算单元了,这是得益于制程工艺和设计水平的提升。
2018年09月27日 17点09分
@涐吢铱舊囿儚 恩,很可能我没有看……也可能是记错……
2018年09月27日 23点09分
1