Project1

标题: if not和unless有什么区别 [打印本页]

作者: DeathKing    时间: 2010-7-4 21:17
标题: if not和unless有什么区别
本帖最后由 DeathKing 于 2010-7-5 02:00 编辑

NetBeans中首选项有这么一项:“将if取反语句变为unless”,我不知道有什么区别,就用Benchmark库做了下面的测试。

希望没有什么语法错误
  1. require 'Benchmark.rb'

  2. TEST_TIMES = 9999999
  3. TEST_STATE = false

  4. Benchmark.bmbm(15) do |t|
  5.         t.report("if not")  {
  6.                 TEST_TIMES.times do
  7.                         if not TEST_STATE
  8.                                 true
  9.                         end
  10.                 end
  11.         }
  12.         t.report("unless") {
  13.                 TEST_TIMES.times do
  14.                         unless TEST_STATE
  15.                                 true
  16.                         end
  17.                 end
  18.         }
  19. end
复制代码
结果是这样的:
  1. Rehearsal --------------------------------------------------
  2. if not           3.954000   0.000000   3.954000 (  4.109375)
  3. unless           3.593000   0.000000   3.593000 (  3.730469)
  4. ----------------------------------------- total: 7.547000sec

  5.                      user     system      total        real
  6. if not           4.219000   0.000000   4.219000 (  4.281250)
  7. unless           3.625000   0.000000   3.625000 (  3.699219)
复制代码
明显unless要快,是因为if not要计算两次么?
作者: 八云紫    时间: 2010-7-4 21:23
估计是 if not 先取反再判断, unless 直接判断~
作者: zhangbanxian    时间: 2010-7-4 21:30
if not是两步,unless是一步,自然是unless快了...- -b话说lz思考问题真精确
作者: 小幽的马甲    时间: 2010-7-4 21:44
  if not true and false---》不满足

  unless true and false---》满足

not的优先权问题,速度在RM里倒真看不出来……毕竟是位运算嘛

作者: 逆鳞R    时间: 2010-7-4 22:04
提示: 作者被禁止或删除 内容自动屏蔽
作者: wangswz    时间: 2010-7-4 22:07
我都以为走错了
看新手贴看多了
现在突然看到技术贴 我的裤裆立刻就湿润了
作者: 小角色    时间: 2010-7-4 22:21
很惊艳。。之前一直觉得只是写法不同以适应不同编程习惯的人
作者: 紫苏    时间: 2010-7-5 00:00
其实这属于架构不独立的细节问题,我刚用你的代码在 Linux AMD Opteron 2CPU/8GB/Sun Fire X4200 上测试,结果是:

  1. Rehearsal --------------------------------------------------
  2. if not           3.520000   0.580000   4.100000 (  4.102890)
  3. unless           3.160000   0.500000   3.660000 (  3.667306)
  4. ----------------------------------------- total: 7.760000sec
  5.                      user     system      total        real
  6. if not           3.150000   0.500000   3.650000 (  3.649854)
  7. unless           3.140000   0.700000   3.840000 (  3.843158)
复制代码
运行时环境稳定下来后似乎也不见得有啥区别
然后试了下 Solaris 4CPU/8GB/Sun V440
  1. Rehearsal --------------------------------------------------
  2. if not          22.170000  34.620000  56.790000 ( 56.824471)
  3. unless          23.200000  34.020000  57.220000 ( 57.239640)
  4. --------------------------------------- total: 114.010000sec

  5.                      user     system      total        real
  6. if not          21.620000  35.040000  56.660000 ( 56.664212)
  7. unless          22.950000  33.930000  56.880000 ( 56.911735)
复制代码
也没看出明显区别

从形式语言的翻译规则上来看,前者是应该先取反,然后分歧跳转,而后者直接分歧跳转。但实际上解释器也会做相应的优化,比如 if not expr 这种语法,解释器完全可以翻译成:

        cmp eax 0                    ; 假设这里 eax 是 expr 解析后的结果值
        je if_not
         ; ..... if not not false
if_not:
        ; ...... if not false

而不是:
        not eax
        cmp eax 1
        je if_not
         ; ..... if not not false
if_not:
        ; ...... if not false

当然上面的指令只是针对 x86,不同的架构也可能有不同的表现
作者: darkdrium    时间: 2010-7-5 00:29
愚以为4.2和3.6不算区别,更何况这是9999999次重复的累计时间,少量操作根本不是可见的差异
另外评价时间应该还要加上复合条件判断的时间,比如if not xxx and xxx和unless xxx or xxx
作者: DeathKing    时间: 2010-7-5 00:37
愚以为4.2和3.6不算区别,更何况这是9999999次重复的累计时间,少量操作根本不是可见的差异
另外评价时间应 ...
darkdrium 发表于 2010-7-5 00:29



复合条件最后也不是要转化为true和false么?
作者: darkdrium    时间: 2010-7-5 00:42
回复 DeathKing 的帖子
优先级应该会影响效率的
比如unless的优先级应该比and和or都低,而if not中not的优先级应该比较高
if (not xx) and (xx)和unless (!xx) and xx应该会有区别

以上皆为未测试的猜测。。。我自重去了- -

   
作者: DeathKing    时间: 2010-7-5 00:44
回复
优先级应该会影响效率的
比如unless的优先级应该比and和or都低,而if not中not的优先级应该比较高
if ...
darkdrium 发表于 2010-7-5 00:42


我的原意是if not p和unless p啊。
p为复合条件(的真伪值)。



作者: darkdrium    时间: 2010-7-5 00:47
回复 DeathKing 的帖子
oh,先把p用括号复合了么?
那其实我觉得测试结果如1楼所言,应该是无差异才对的- -数量级太低了。。。

话说这个unless,我也是头痛的紧啊,每次看到,脑子都得先转成if not


   
作者: DeathKing    时间: 2010-7-5 00:50
回复
oh,先把p用括号复合了么?
那其实我觉得测试结果如1楼所言,应该是无差异才对的- -数量级太低了。。 ...
darkdrium 发表于 2010-7-5 00:47


我不觉得,有个比较好的点子就是(如果不考虑优先级的问题)

unless p   # (p == false)
  exp
else
  exp
end

而 if 则是 if true而已。

作者: 紫苏    时间: 2010-7-5 00:52
具体看解释器是如何实现的,这个我无从得知,但从汇编方面分析,差别基本上可以无视,就像当年某高手煞有介事的强调 i++ 和 ++i 的区别一样
作者: darkdrium    时间: 2010-7-5 00:58
本帖最后由 darkdrium 于 2010-7-5 01:00 编辑

回复 紫苏 的帖子

本来想点评的,结果回复了自己一个空帖子,防止被版主抓到而已灌水,将点评放到这里了。。。

从人类语言的角度来讲,它应该还有个否则。。。所以个人觉得挺别扭。比如:除非明天下雨,(否则)我们去吃火锅

   
   
作者: DeathKing    时间: 2010-7-5 00:59
回复 紫苏 的帖子

的确,i++和++i的区别貌似还是很大。

应该就是这个意思,貌似和“结合能力”扯上关系:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int i = 1,a,b;
  5. a = i++;
  6. b = ++i;
  7. printf("%d %d %d",i,a,b);
  8. }
复制代码
输出 3 1 3

++i 是先自加i然后再复制,i++则相反?
作者: darkdrium    时间: 2010-7-5 01:00
回复 DeathKing 的帖子
。。。他应该是说效率上的差别。。。

   
作者: darkdrium    时间: 2010-7-5 01:03
回复 DeathKing 的帖子
。。。他应该是说效率上的差别。。。

   
作者: DeathKing    时间: 2010-7-5 01:03
回复

本来想点评的,结果回复了自己一个空帖子,防止被版主抓到而已灌水,将点评放到这里了。。。

从人 ...
darkdrium 发表于 2010-7-5 00:58


我们英语老师说,unless你别翻译为除非,要翻译为“如果不”。{:nm_3:}

作者: 紫苏    时间: 2010-7-5 01:12
回复 DeathKing 的帖子

呵呵,对的,不过我说的是效率,i++ 要额外使用一个寄存器保存 i 的值作为返回值,然后再把 i 加 1,而 ++i 直接把 i 加 1,返回 i
这个区别在硬件飞速发展的今天已经是微乎其微了,虽然很多高手还是坚持“效率完美主义”,但我觉得应该把精力放在分析算法复杂度上,那才是大头儿
作者: DeathKing    时间: 2010-7-5 01:14
回复

呵呵,对的,不过我说的是效率,i++ 要额外使用一个寄存器保存 i 的值作为返回值,然后再把 i 加 1 ...
紫苏 发表于 2010-7-5 01:12


效率这种事应该要交给解释器或者编译器来优化,然后自己再在解释器或者编译器那里效率完美主义。

觉得NOI除了搞算法剩下的也只有效率完美主义了。

作者: darkdrium    时间: 2010-7-5 01:16
回复 DeathKing 的帖子

要效率就不要ruby了,ruby发明的初衷,就是为了解放程序员的,现在的计算机,运算效率已经很高了,没必要为了那么点效率苦了程序员


   
作者: 紫苏    时间: 2010-7-5 01:20
回复

本来想点评的,结果回复了自己一个空帖子,防止被版主抓到而已灌水,将点评放到这里了。。。

从人 ...
darkdrium 发表于 2010-7-5 00:58


哦,理解错了,但至少英语语法里不需要那个“否则”的:
unless it rains tomorrow, we would go out.
可能用在句末更顺口,Ruby 也支持这样的语法:
goOut() unless rain
作者: 紫苏    时间: 2010-7-5 01:33
本帖最后由 紫苏 于 2010-7-5 06:19 编辑

解释性语言运行程序的效率确实没有直接执行编译好的机器码高,但她的一大特点就是调试周期比编译性语言的周期短(这个周期的过程,前者是:编辑代码 - 解释 - 调试;后者是:编辑代码 - 编译链接 - 运行 - 调试)。解释性语言只需要整体分析一下语法,然后就马上开始执行第一条语句,而编译性语言在语法分析的同时还需要把所有代码编译为机器可读的二进制码,然后把不同的对象文件链接起来。这在制造原型和测试的时候就比较重要了,你调试的次数越多,就越能通过使用解释性语言来节省时间。编译性语言虽然也有一些优化速度的机制,如预编译文件,但整体还是不如解释性语言

恩,matz的确是这样想的,所以就抛弃了指针?

DeathKing 发表于 2010-7-5 01:14


其实不要指针的原因是多方面的,其中一个比较重要的是为了在内存托管机制下减少堆内存碎片——在大多数现代高级语言中,只要是有垃圾回收机制的,都不会提供指针。在堆中分配的内存通常都是零散的(这也是为什么这种内存区域叫“堆”,顾名思义,没有次序的一堆),会导致堆内存中产生很多碎片,而当对象被垃圾回收后,GC 就会紧缩内存,整理碎片,这样才能提高分配堆内存的效率(因为分配堆内存需要在“杂乱的一堆”中找到一块足够大的连续空间)。这样一来,就需要把内存中的对象移来移去,自然指向这个对象的引用的地址也会改变。由于所有该对象的引用在底层都是指向同一个指针(而这个对象唯一的指针又指向该对象),所以只需要改变这个指针的值,就能改变所有引用指向的值。但这在 C++ 中却是不可能的,因为 C++ 可以操纵任意数量的指针指向任意地址
除此之外还有其它原因,比如安全性:有指针就有可能导致内存泄漏,崩溃,访问不可访问、释放已被释放的地址而导致段错误等,引用则不会出现这些问题




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1