代码之家  ›  专栏  ›  技术社区  ›  0x.dummyVar

Haxe:将变量映射为两个值之一的效率

  •  1
  • 0x.dummyVar  · 技术社区  · 6 年前

    我觉得这个问题太笼统,问得不好如有改进建议,将不胜感激。

    假设我有一个整型变量,我需要将它转换成另外两个值中的一个如果变量为0,它将保持0,否则,它将变为1我可以想出两种方法。

    方法1: 内联if/else赋值。

    function runFunc(input:Int):Void
    {
        <script>
    }
    
    for (index in 0...5)
    {
        runFunc(if (index == 0) {0;} else {1;});
    }
    

    方法2: 除法和舍入法。

    function runFunc(input:Int):Void
    {
        <script>
    }
    
    for (index in 0...5)
    {
        runFunc(Math.round(index / index));
    }
    

    方法1 更为标准化,适用于其他数据类型和其他值,但是 方法2 似乎它需要更少的处理能力(尤其是如果这几乎需要经常进行)。

    假设 方法2 舍入不会有问题,这两种方法在时间上是否有足够的差异来考虑使用其中一种方法if/else语句和Math.round()之类的不同语句如何影响处理时间?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Jeff Ward    6 年前

    好吧,首先,你的 方法2 除以零所以这甚至不是一个有效的解决方案。

    不过,我想你想要一个“一般”的答案当然,这类问题伴随着大量的“取决于”资格它取决于CPU的类型、编程语言、编译器可能进行的优化、运行时优化等。

    然而,一般而言,相关业务的成本顺序大致如下:

    1. 逻辑运算和算术运算最便宜
      • 其中整数运算比浮点运算便宜。
    2. 分支(ifs和循环)的成本适中。
    3. 这个部门的价格适中。
    4. 函数调用非常昂贵。

    基本上,这是因为(分别):

    1. 这就是CPU所做的,它们经过优化,可以快速完成
    2. 分支表示两种可能的路径,这会减慢CPU并行化和优化的速度。
    3. 划分是一个多步骤的过程。
    4. 函数调用必须推送并弹出堆栈。

    所以,我可能会打赌 方法1 上面为了清楚起见,我将在第一个例子中用等价的三元运算符编写if语句:

    for (index in 0...5)
    {
        runFunc( index==0 ? 0 : 1 );
    }
    

    这对于映射一个简单的布尔值(索引为0或不是0)是很好的但是当映射变得更复杂时呢在将一个值映射到另一个值时,有两个结构通常会提供良好的性能:查找表或哈希映射。

    如果键是整数,在一些最小值和最大值之间有限制,那么查找表是有用的。如果密钥是散列的(通常可以使用int、string或Objects作为散列密钥),那么散列映射是很好的看看 haxe.ds.IntMap , haxe.ds.StringMap haxe.ds.ObjectMap .)

    例1: 一个常用的查找表可以将数字整数“星期几”映射到用于该天的单词假设 day:Int 始终为0-6,日整数到字符串查找表将为:

    var day_name_lut = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ];
    

    所以现在 trace('Today is a '+day_name_lut[Date.now().getDay()]); tell us 今天是星期几它将一个整数映射到 非常 低成本比函数调用或 IntMap<String> .

    例2: 一个 sample StringMap可用于按字符串值存储某些对象(例如 Person 他们的 name )这将允许我们以后按姓名查找人员:

    var people_by_name = new StringMap<Person>();
    var joe = new Person("Joe");
    people_by_name.set(joe.name, joe);
    var bob = new Person("Bob");
    people_by_name.set(bob.name, bob);
    

    这在缓存昂贵的操作时非常常见。 Imagine caching an HTTP response 通过它的网址会是的 许多的 从StringMap第二次查找要比再次返回获取响应便宜。

    ---更新---

    我还注意到你说的“内联if/else赋值”,指的是:

    runFunc(if (index == 0) {0;} else {1;});
    

    注意,实际上编写if内联是 绝对不行 性能差异它的性能与:

    var tmp = if (index == 0) {0;} else {1;}
    runFunc(tmp);
    

    这些也完全一样:

    runFunc( if (index == 0) 0 else 1);
    runFunc( (index == 0) ? 0 : 1);
    

    这些类型的语义差异对代码的最终执行没有任何影响处理器仍然需要计算并临时存储调用该函数的值,不管是内联编写的,还是存储在 tmp 变量,或使用if/else或三元运算符编写分支编译器和vm经过优化,可以获取(可能是可变的)代码,并将其归结为目标CPU的最佳指令。

        2
  •  0
  •   KevinResoL    6 年前

    二进制运算如何 index & 1 ?