Board logo

标题: [其他] [已结束]电脑处理1*1和1234567*134567一样快吗? [打印本页]

作者: qzwqzw    时间: 2011-3-14 22:27     标题: [已结束]电脑处理1*1和1234567*134567一样快吗?

本帖最后由 qzwqzw 于 2011-4-30 17:25 编辑

辩论已结束
对于非计算机原理专业的论坛
能讨论到如此程度
我是十分意外并且高兴的
主要是因为几位重量级人物的参与
包括
持支持意见的理论派wc726842270
持中立意见的技术流neorobin
持反对意见的实证家zm900612

至于最后的结论
我想是不用总结的
任何论点都会受到多方面因素的影响
包括它所处的环境和所讨论的深度
不过就此论点来说
目前为止反对派占明显的大多数
而且正方的意见到目前为止都不够有力
这说明反对和中立的意见是当前的主流意识
——————————————————————
首先声明
这并非批处理编程直接相关的问题
而是因为一个批处理而衍生的问题
版主大大不要见怪

理所当然
对于人脑来说
1234567*1234567明显比1*1消耗更多的能量和时间
那么对于电脑来说
也是如此吗?

请大家畅所欲言——
注意:
据我的测试
一旦选择“支持正方”或“支持反方”后
即选定了辩论立场且无法中途改变
所以请谨慎选择支持立场!


另外,
如果觉得某个回复很棒很合自己心意
请不要忘记投上自己赞成的一票

[ 本帖最后由 qzwqzw 于 2011-3-15 11:01 编辑 ]
作者: qzwqzw    时间: 2011-3-14 22:33     标题: 测试一下辩论回复

第一张正方回复仅为测试
请不要在此投票

[ 本帖最后由 qzwqzw 于 2011-3-15 11:03 编辑 ]
作者: CrLf    时间: 2011-3-14 22:33

我在想,如果乘法是通过加法实现的,那1*10000000和100000000*1的效率是否有别呢?对人来说,这是荒谬的,但是假如电脑是很死板的把X加N次,那二者效率很可能有所不同,当然了,估计就算真的是把某个数加N次,也很可能是先判断二者大小
手上尚无测试结果,暂且中立
作者: CrLf    时间: 2011-3-14 22:53

构造了两个个数十兆的超大bat,有了理论支持,果断反方:
  1. @echo off&setlocal enabledelayedexpansion
  2. for %%a in (1 40000) do (
  3. set s=%%a*%%a
  4. set /a n+=1
  5. for /l %%a in (1 1 9) do set s=!s!,!s!
  6. (
  7. echo @echo off
  8. echo echo %%time%%
  9. for /l %%l in (1 1 10000) do echo set /a !s!
  10. echo echo %%time%%
  11. echo pause)>test!n!.bat
  12. )
  13. pause
复制代码
测试结果(进行了两次):
test1.bat   20.08秒  19.07秒
test2.bat   28.60秒  28.67秒

这很说明问题了,当然了,这是上万次的set叠加才有这么明显的落差,少量使用时差别必定不明显。可惜没时间进行大量测试,无法描绘函数图象,否则应可猜测set /a的工作原理
作者: 随风    时间: 2011-3-15 00:10

猜:应该不一样快吧,除非是有现成的答案只要读取,否则计算的话总有个过程吧,2位数和1位数应该都会有区别,只是不明显。
作者: Batcher    时间: 2011-3-15 10:29

这个要查一查《计算机组成原理》、《汇编语言》等教材了吧
看看它是怎样把乘法转换成加法、实际计算的时候在几个寄存器里面是怎么倒腾的
^_^
作者: wc726842270    时间: 2011-3-15 11:07

个人认为这很明显是取绝于数据复杂程度。电脑的开发也不外乎来自人类的自身思维,我想就这两个数据来看是看不出什么的。“CPU的计算率很高”。这也许需要计算机的低级语言了(或从原理着手),个人认为使用代码计算是不可取的
作者: qzwqzw    时间: 2011-3-15 11:19

嗯,现在正反双方战力是1:2
我是个伪正方
误点击了“支持正方”

3楼的代码自有可取之处
只是需要根据情况再优化一下

4楼的思路是个方向
希望能够更深入

6楼的“CPU的计算率很高”让我很迷惑
看来也需要再答疑解惑一下了
作者: wc726842270    时间: 2011-3-15 11:31

中央处理器的工作速度与工作主频和体系结构都有关系。中央处理器的速度一般都在几个MIPS(每秒执行100万条指令)以上。有的已经达到几百MIPS 。
百度刚找到的,可能不在点子上。从极值的角度来说是差不多的(关键是这个点是什么还不清楚)
作者: caruko    时间: 2011-3-15 22:59

一般来说,电脑处理数值计算跟数值的字节长度有关系。

电脑的二进制加法器电路是通过“异或门”电路跟“与门”电路来计算结果的。
一般的高级语言在计算时都要指定数值精度,比如 8字节的int型数值是0-255。
电脑每次处理8字节int型数值计算时,都需要从最低位计算加到最高位。
所以字节数一样的数,计算时间一样,1+1 跟1+100是一样的。

在一般的程序语言中,“1234567”这个数比“1”明显字节长度更长,加法器需要花更多时间计算。
虽然不确定批处理转换后的数字是多少字节,因为字符跟数字没有分开,不知道如何转换的,或者存储结构是特殊设计的。
但3楼代码可以看出批处理在解释数字时,还是会自动匹配合适字节的数。
作者: CrLf    时间: 2011-3-16 13:06

又做了几个测试:

1*1000000,1000000*1
没有大于0.3秒的差别,但是几次测试,后者始终稍快,说明计算前可能并未比较数字大小

而805306366*2却比127867*12596(乘积均为1610612732)
前者快了近两秒,说明确实与复杂度有关,看来有可能真的是用加法,不过究竟具体操作的时候倍增还是指数增长就不得而知了。

536870912*3,1073741823*3(两个大数分别为10000.....00和11111.....11,二进制位数相同)
没有大于0.3秒的差别,数次测试中,前者始终稍快,说明速度和二进制形态或者十进制字节数有关。

1073741824/2,2147483647/2(同上,只比前一个例子的数多一位二进制位数)
前者快了将近半秒,说明同样的字节(包括十进制和二进制)长度下,速度可能由这个数的二进制形态决定。
作者: qzwqzw    时间: 2011-3-20 11:45

很可惜!
辩论没有向我想象的那个方向发展

好吧
既然选了正方
我就抛出一些正方的观点和证据

下面这段测试代码中
将set /a m=1换成set /a m=1234567
既可以进行对照测试
在我的环境下
总体运行时间在31~32秒之间
而两段程序的时间差小于1.7秒
也就是说两段程序的时间性能差距在%5之间
这个跟四楼的代码大于40%的差距相比
应该算不上明显的差距吧?
  1. @echo off&setlocal enabledelayedexpansion
  2. set /a m=1
  3. echo %time%
  4. for /l %%i in (1,1,1000) do (
  5. for /l %%j in (1,1,1000) do (
  6. set /a s=m*m
  7. )
  8. )
  9. echo %time%
  10. echo %s%
  11. pause
复制代码

作者: CrLf    时间: 2011-3-20 11:48

楼上考虑过for /l循环本身的用时吗?
作者: CrLf    时间: 2011-3-20 11:53

不过仔细想想,也许正是因为语句的字符长度不同导致预处理时间相异,所以4楼代码才会有这么明显的差别。
仅仅个人猜测而已,未验证
作者: qzwqzw    时间: 2011-3-20 12:08

嗯,预处理
终于有人想到了这个
嗯再贴一段ANSI C代码
把1234567*7654321换成1*1
即可进行比照测试
我使用WinTC2编译链接后
放在批处理中测试
两段程序的耗时均为59.06秒
时间性能差距小于10ms
这又说明什么问题呢?

  1. #include "Stdio.h"
  2. int main(void)
  3. {
  4. long i,j,s;
  5. i=j=s=0;
  6. for (i=0;i<100000;i++)
  7.    for (j=0;j<100000;j++)
  8.      s=1234567*7654321;
  9. }
复制代码

作者: CrLf    时间: 2011-3-20 12:51

但是楼上似乎忽略了set命令本身也有启动耗时,一次计算耗时和一次启动耗时应该相差很大的,我写了以下代码验证,结果证明1*1与1234567890*1234567890的耗时分别为13秒与17秒
  1. @echo off&setlocal enabledelayedexpansion
  2. set s=1*1
  3. title %s%
  4. for /l %%a in (1 1 9) do set s=!s!,!s!
  5. echo %time%
  6. for /l %%i in (1,1,20000) do (
  7.      set /a %s%
  8. )
  9. echo %time%
  10. pause
复制代码

作者: CrLf    时间: 2011-3-20 13:03

set本身也有启动耗时,并且应该远远大于计算耗时,所以需要以set /a n*n,n*n的形式来尽量缩小启动用时所占的百分比
我写了一段代码来证明,1*1与1234567890*1234567890耗时分别为13秒与17秒,证明计算耗时是存在的,并且相差很大
  1. @echo off&setlocal enabledelayedexpansion
  2. set s=1234567890*1234567890
  3. title %s%
  4. for /l %%a in (1 1 9) do set s=!s!,!s!
  5. echo %time%
  6. for /l %%i in (1,1,20000) do (
  7.      set /a %s%
  8. )
  9. echo %time%
  10. pause
复制代码

作者: hanyeguxing    时间: 2011-3-20 19:17

以楼主给出的这两对数字,以32位系统来说,速度是一样的
作者: qzwqzw    时间: 2011-3-21 13:20

set本身也有启动耗时,并且应该远远大于计算耗时,所以需要以set /a n*n,n*n的形式来尽量缩小启动用时所占的百分比
我写了一段代码来证明,1*1与1234567890*1234567890耗时分别为13秒与17秒,证明计算耗时是存在的, ...
zm900612 发表于 2011-3-20 13:03

看不出你的这段代码与以前的有什么本质上的不同
启动耗时当然会有(我这里理解为将命令加载到内存并进行预处理的耗时)
而且也有可能确实大于计算耗时(我这里理解为命令在内存中参与运算和执行的耗时)
但你的代码如何能证明启动耗时与计算耗时相差极大?
你确认你的代码对于1*1和1234567890*1234567890
他们的启动耗时(具体的说就是对命令行的预处理)是一样的吗?
如果不是一样的
你又如何比较计算耗时的差别呢?
作者: CrLf    时间: 2011-3-21 13:40

好吧,那我们来总结一下,暂时把一句set /a的耗时划分为六部分:
1、语块的预处理耗时
2、变量延迟耗时
3、set命令的启动耗时
4、算式的预处理耗时
5、读取变量耗时
6、计算耗时(实际操作的时候不知道是否和第四部分同时完成)
7、赋值耗时

在这几部分中,1、2、3部分的耗时浮动可以多次测试用平均值尽量排除,而第5、7部分在我的测试代码中不存在,也就是说,我们现在争论的焦点是不同情况下“算式的预处理耗时”之间和“计算耗时”之间的差异。
这一点用批处理似乎没办法验证吧?
作者: wayaoqiang    时间: 2011-3-21 13:52

听说, 真理是掌握在少数人手里的, 我看正方人少, 就支持了下
作者: qzwqzw    时间: 2011-3-21 14:17

本帖最后由 qzwqzw 于 2011-3-21 14:22 编辑
不同情况下“算式的预处理耗时”之间和“计算耗时”之间的差异。
这一点用批处理似乎没办法验证吧?

我是否可以理解为
你已经取消了以前“计算耗时是存在的,并且相差极大”的论断?

正如你说
计算耗时与预处理耗时难以严格区分
但是你从我的批处理代码仍然没有看出什么吗?

是的
1*1和1234567*1234567必然会有预处理上的差异
我们所能做的只有尽量减少这部分差异
所有我使用了从内存变量中读取操作数的做法
那比从命令行读取操作数要快很多
相对而言耗时差异也会缩小
作者: CrLf    时间: 2011-3-21 16:32

这个是我没考虑周全,我原以为读取变量会慢些,所以当时没细想。但是楼上既然知道启动耗时大于一次计算耗时,那为什么一次set中只计算一次呢?这样一来计算耗时之差会被set启动耗时淹没,自然不明显了。我用set /a 1*1,1*1,1*1,1*1....的办法就是为了让计算耗时所占比重最大化。
  1. @echo off&setlocal enabledelayedexpansion
  2. set n=1&set s=n*n
  3. for /l %%a in (1 1 9) do set s=!s!,!s!
  4. title %n%
  5. echo %time%
  6. for /l %%i in (1,1,10000) do (
  7.      set /a %s%
  8. )
  9. echo %time%
  10. pause
复制代码
结果n=1时耗时39秒,n=1234567890时耗时44秒,这又作何解释呢?
作者: CrLf    时间: 2011-3-21 16:37

至于15楼的代码,我不懂编程,但是从vbs和bat的差别中猜测编程的计算方法、赋值方式完全不同于bat,所以exe的计算速度远快于cmd,生命游戏就是一个例子,可以exe版和bat版生命游戏来对比出同尺寸图、同样代数的用时
作者: caruko    时间: 2011-3-21 16:41

本帖最后由 caruko 于 2011-3-22 12:48 编辑

楼上,你将S设为INT型,差距应该比10MS大

呃,我说的是15楼
作者: CrLf    时间: 2011-3-21 16:57

批处理怎么设值变量类型??
作者: wayaoqiang    时间: 2011-3-21 18:44

那个, 加法的汇编指令就一条, 乘法的汇编指令也是一条

虽然, 不同指令, 速度很可能不一样, 但是, 运行一条指令, 时间几乎可以忽略不计

而加法, 乘法指令, 是内置的, 速度, 应该差不到哪里去, I see.
作者: CrLf    时间: 2011-3-21 18:51

不懂编程,不过我觉得如果乘法只是加法集合成的函数,那不见得速度一样快
作者: qzwqzw    时间: 2011-3-21 20:25

本帖最后由 qzwqzw 于 2011-3-21 20:37 编辑


现在问题的讨论方向终于有些触及我所思考的核心了

对于23楼的程序我的解释是这样的
虽然你降低了命令启动的次数
但是仍然没有完全排除计算前读取时间的差异
反而是扩张了这部分差异的影响
从一个变量中读一个字符和一个字符串的差异是很明显的

关于这一点你将测试数据改为
123456789*123456789  (=15241578750190521)

987654321*987654321  (=975461057789971041)
就会体会到了
这两组数据的结果差值甚至大于1*1与123456789*123456789结果插着
但实际前两组数据的运行时间几乎是相同的
作者: CrLf    时间: 2011-3-21 20:43

stop,要想不跑偏必须先统一一下意见,因为以后的讨论可能是以此为前提的:
1、set 命令读取变量时的速度快于预处理解释字符串的速度,也就是说set /a m=n(此时n=1)真的快于set /a m=1吗?
2、set 命令读取变量的速度是否取决于变量的字符串长度?

暂时没时间做实验,证明这两个假设的工作先交给诸位了哈...
作者: CrLf    时间: 2011-3-21 20:46

至于set命令内部预处理的耗时,请参考11楼测试结果,虽然结果相同时速度仍有差异,但是预处理并非决定性因素。
作者: wc726842270    时间: 2011-3-22 02:05

怎么感觉跑题了。如果使用代码来测试,很可能人为的增加了其复杂程度,对此个人比较相信低级语言(计算机语言,汇编语言),当前我们用的都是32位机(除了服务器外),而CPU也随之强大了。单单从人类的角度来看,这几乎是没有差距的。感觉上就像光走了1000M和走了1M的时间似的。在数学上可以说是相同的
作者: jinzeyu    时间: 2011-3-31 19:41

1*1那个
19:39:18.01
19:39:18.29
1234567*1234567那个
19:39:18.31
19:39:18.59
作者: mxxcgzxxx    时间: 2011-3-31 20:30

绝对是有差别的,计算机只是算得快并不是算得巧,追朔到最原本的电路开关上不论是什么只有0和1的差别,所以不论是加减还是乘除都是在做加法运算,只是正序还是倒序的问题.
所以虽然在一般计算中时间差别很微小(由于CPU能力太强),但累加到一定数量时还是会出现差别的!

当然程序的编程优化可以改变时间的最终结果,但也只能做到均衡,无法在极端条件下也做到一样快,
从绝对时间观上说是一定有区别的,不论是千分之一秒还是万分之一秒!不论你是否能感觉到!
差别依然还是有的!
作者: mxxcgzxxx    时间: 2011-3-31 21:17

为了证实这个推论,首先要做出计算公式,另外要有科学的验证观,不可以只凭一次数据就下结论,
因此我发现计算机的其它软件也会影响结果,我运行时把网络和所有的应用程序都退出了.
为了更加准确我把程序写了两次,将计算互换位置以验正计算结果的真实性与无干涉性.
并做了反复循环以让大家利用平均数来进行验正.
另外为了不受开程序时鼠标点击和键盘的缓冲影响特加了多行空显,所以所有语句都是有用的!
  1. @echo off
  2. :xx
  3. echo.
  4. echo.
  5. echo.
  6. echo.
  7. echo.
  8. echo.
  9. echo 开始计算 1*1 用时如下:
  10. set t=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  11. for /l %%i in (1,1,10000) do set/a b=1*1
  12. set t1=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  13. set/a t2="%t1%"-"%t%"
  14. echo 用时0.%t2%秒
  15. echo.
  16. echo.
  17. echo.
  18. echo.
  19. echo 开始计算 1234567*134567 用时如下:
  20. set t=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  21. for /l %%i in (1,1,10000) do set/a b=1234567*134567
  22. set t1=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  23. set/a t2=%t1%-%t%
  24. echo 用时0.%t2%秒
  25. pause
  26. echo.
  27. echo.
  28. echo.
  29. echo.
  30. echo.
  31. echo.
  32. echo 开始计算 1234567*134567 用时如下:
  33. set t=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  34. for /l %%i in (1,1,10000) do set/a b=1234567*134567
  35. set t1=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  36. set/a t2="%t1%"-"%t%"
  37. echo 用时0.%t2%秒
  38. echo.
  39. echo.
  40. echo.
  41. echo.
  42. echo 开始计算 1*1 用时如下:
  43. set t=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  44. for /l %%i in (1,1,10000) do set/a b=1*1
  45. set t1=%time:~0,2%%time:~3,2%%time:~-5,2%%time:~-2,2%
  46. set/a t2=%t1%-%t%
  47. echo 用时0.%t2%秒
  48. pause
  49. goto xx
复制代码
我的结果是10000次1*1在0.22秒左右,1234567*134567在0.26秒左右.
发现这个程序还可以用来测试当前计算机的运行能力,如果时间加长了一定有什么软件在占用内存呵!
希望能满意我的答复!
作者: neorobin    时间: 2011-3-31 21:39

1. 1*1 这在任何一台电脑上都不会超出 单字节(8 位) 整型数运算范围, 也不会超出最小字长 8 位
所需要的时间无疑是 乘法运算里 最少的.

2.
两个大数以及它们的积的十六进制表示如下:

1234567
12D687

134567
20DA7

166131977489
26AE3CCD11

两个大乘数都在 4 字节以内, 而积却超出了 4 字节(32 位).
现在我们使用的多数 PC 机都是 32 位机, 直接作为整型数计算会产生溢出, 这种情况下会是很不一样的.

用 32 位机的 RISC 指令集肯定是不能直接计算得到结果的, 得有程序支持才行.

而在 64 位(8字节)及 64 位以上的机器上, 乘数和积的存储长度都没有超出,
运算器的设计就可能让 1*1和1234567*134567 都是花费一个同样的最少的计算时间, 换而言之,
现在的 CPU 核心电路设计和 RISC 指令可以(或将会)实现:
当 操作数 和 理论计算结果 在同一个 整型数据类型 的计算范围内时, 任何小的数的运算和任何大的数的运算
都将花费同样多的时钟周期, 也就是费时一样长.

最终观点: 1*1 和 1234567*134567 在 32 位及以下的机器上会有很大的耗时差异, 而在 64 位及以上
的机器上已经实现(或将会实现)耗时完全相同.
作者: neorobin    时间: 2011-3-31 21:46

各位想要实际测试的朋友: 至少 要用同样的 汇编代码 分别在一个 <=32位的机器 和 一个 >=64位的机器上分别做测试
作者: neorobin    时间: 2011-3-31 22:18

以下引用 wikipedia 对 RISC 和 CISC 的相关阐述 进一步阐明我的观点: 1*1和1234567*134567, 因机器字长及CPU核心电路设计 以及 核心指令设计方案而不同, 可能耗时差异很大, 也可能都只需要耗时 1 个时钟周期.
http://zh.wikipedia.org/wiki/%E7%B2%BE%E7%AE%80%E6%8C%87%E4%BB%A4%E9%9B%86

...
另一方面,目前最常见的复杂指令集x86 CPU,虽然指令集是CISC的,但因对常用的简单指令会以硬件线路控制尽全力加速,不常用的复杂指令则交由微码循序器“慢慢解码、慢慢跑”,因而有“RISCy x86”之称。
...
复杂指令集(CISC)
例如:Intel的奔腾系列中央处理器属于复杂指令集(x86)结构,而IBM的PowerPC 970(用于苹果机Power Mac G5)中央处理器属于精简指令集(POWER)结构。但是自从 Intel Pentium Pro(P6)之后,x86复杂指令集的CPU也开始采用内核精简指令集,而在外围布置从复杂指令集到精简指令集的译码电路动态译码方式,籍此提高CPU的性能,使复杂指令集CPU也有可能在1个时钟周期内运行一条甚至多条指令




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2