zoukankan      html  css  js  c++  java
  • php 的加法

    无意间看到了php中关于加,减,乘,除 的计算方法

    这里

    http://lxr.php.net/source/xref/PHP-5.6/Zend/zend_operators.h#596

    static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
    597{
    598    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
    599        if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
    600#if defined(__GNUC__) && defined(__i386__)
    601        __asm__(
    602            "movl    (%1), %%eax
    	"
    603            "addl   (%2), %%eax
    	"
    604            "jo     0f
    	"
    605            "movl   %%eax, (%0)
    	"
    606            "movb   %3, %c5(%0)
    	"
    607            "jmp    1f
    "
    608            "0:
    	"
    609            "fildl    (%1)
    	"
    610            "fildl    (%2)
    	"
    611            "faddp    %%st, %%st(1)
    	"
    612            "movb   %4, %c5(%0)
    	"
    613            "fstpl    (%0)
    "
    614            "1:"
    615            :
    616            : "r"(&result->value),
    617              "r"(&op1->value),
    618              "r"(&op2->value),
    619              "n"(IS_LONG),
    620              "n"(IS_DOUBLE),
    621              "n"(ZVAL_OFFSETOF_TYPE)
    622            : "eax","cc");
    623#elif defined(__GNUC__) && defined(__x86_64__)
    624        __asm__(
    625            "movq    (%1), %%rax
    	"
    626            "addq   (%2), %%rax
    	"
    627            "jo     0f
    	"
    628            "movq   %%rax, (%0)
    	"
    629            "movb   %3, %c5(%0)
    	"
    630            "jmp    1f
    "
    631            "0:
    	"
    632            "fildq    (%1)
    	"
    633            "fildq    (%2)
    	"
    634            "faddp    %%st, %%st(1)
    	"
    635            "movb   %4, %c5(%0)
    	"
    636            "fstpl    (%0)
    "
    637            "1:"
    638            :
    639            : "r"(&result->value),
    640              "r"(&op1->value),
    641              "r"(&op2->value),
    642              "n"(IS_LONG),
    643              "n"(IS_DOUBLE),
    644              "n"(ZVAL_OFFSETOF_TYPE)
    645            : "rax","cc");
    646#else
    647            /*
    648             * 'result' may alias with op1 or op2, so we need to
    649             * ensure that 'result' is not updated until after we
    650             * have read the values of op1 and op2.
    651             */
    652
    653            if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
    654                && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) {
    655                Z_DVAL_P(result) = (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2);
    656                Z_TYPE_P(result) = IS_DOUBLE;
    657            } else {
    658                Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2);
    659                Z_TYPE_P(result) = IS_LONG;
    660            }
    661#endif
    662            return SUCCESS;
    663        } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
    664            Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2);
    665            Z_TYPE_P(result) = IS_DOUBLE;
    666            return SUCCESS;
    667        }
    668    } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
    669        if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
    670            Z_DVAL_P(result) = Z_DVAL_P(op1) + Z_DVAL_P(op2);
    671            Z_TYPE_P(result) = IS_DOUBLE;
    672            return SUCCESS;
    673        } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
    674            Z_DVAL_P(result) = Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2));
    675            Z_TYPE_P(result) = IS_DOUBLE;
    676            return SUCCESS;
    677        }
    678    }
    679    return add_function(result, op1, op2 TSRMLS_CC);
    680}

    其中第653行中的宏 LONG_SIGN_MASK 定义为

    #define LONG_SIGN_MASK (1L << (8*sizeof(long)-1))

     在64位机下,LONG_SIGN_MASK的值为 1L<< (8*8-1) = 1L<<63 = 2^63次方

    Intel IA32 浮点运算

    IA32处理器和很多其它一些处理器一样,有专门用于保存浮点数的寄存器,当在cpu中进行浮点数运算时,这些寄存器就用来保存输入输出及相关的中间结果。

    但IA32有一个比较特别的地方,它的浮点数寄存器是80位的,而我们在程序中只用到32和64位两种类型,因此当把float,double放入到cpu中时,它们都会先被转换成了80位,然后以80位的方式进行运算,最后得到的结果再转换回来。这样特性使得浮点数的计算可以相对更精确些,但同时,一不小心很可能也会引出一些意想不到的问题。

    你可能突然恍然大悟了,对的,我们最开始提到那个奇怪的问题就与此相关。

    s/e得到结果是个80位的浮点数,由这个浮点数先转换成double再转成int,与直接就转换成int,结果很可能是不同的。

    比如在我们的例子中,s/e ~ 29.999999....时,s/e转换成double使用round-to-even的方式,会得到也许是30.0000001,再转成整形时,得到30.

    但如果直接由29.99999...转换成整型,得到却是29。

    后来新出的系列Intel处理器,包括IA32及64位的处理器,提供了专门的硬件来直接处理浮点数,使得可以分开对待float型与double型,这些硬件特性在compiler的支持下,可以生相对高效的代码,同时也避免了我们上面所遇到的问题,有兴趣的读者可以google一下相关的关键字:sse。

     在64位机下
    int           4个字节

    long         8个字节

    double        8个字节

    float         4个字节

    double long  8个字节

    指针         8个字节

    而在32位机下

    int            4个字节

    long         4个字节

    double        8个字节

    float         4个字节

    double long  8个字节

    指针                 4个字节

  • 相关阅读:
    Android底部菜单栏的两种实现方式 附完整源码
    如何创建WebView
    实现 unity MonoBehaviour API5.4 的消息
    linux常用命令2
    Mac 自带的Apache php 狼神的
    高频sql语句汇总。不断更新。。
    4.数据库mysql相关
    Android keystore文件查看应用签名md5
    Java 多线程进阶-并发协作控制
    Java 多线程进阶-并发数据结构
  • 原文地址:https://www.cnblogs.com/taek/p/6067652.html
Copyright © 2011-2022 走看看