博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
php 的加法
阅读量:5052 次
发布时间:2019-06-12

本文共 4326 字,大约阅读时间需要 14 分钟。

无意间看到了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\n\t"603            "addl   (%2), %%eax\n\t"604            "jo     0f\n\t"605            "movl   %%eax, (%0)\n\t"606            "movb   %3, %c5(%0)\n\t"607            "jmp    1f\n"608            "0:\n\t"609            "fildl    (%1)\n\t"610            "fildl    (%2)\n\t"611            "faddp    %%st, %%st(1)\n\t"612            "movb   %4, %c5(%0)\n\t"613            "fstpl    (%0)\n"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\n\t"626            "addq   (%2), %%rax\n\t"627            "jo     0f\n\t"628            "movq   %%rax, (%0)\n\t"629            "movb   %3, %c5(%0)\n\t"630            "jmp    1f\n"631            "0:\n\t"632            "fildq    (%1)\n\t"633            "fildq    (%2)\n\t"634            "faddp    %%st, %%st(1)\n\t"635            "movb   %4, %c5(%0)\n\t"636            "fstpl    (%0)\n"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#else647            /*648             * 'result' may alias with op1 or op2, so we need to649             * ensure that 'result' is not updated until after we650             * have read the values of op1 and op2.651             */652653            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#endif662            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个字节

 

转载于:https://www.cnblogs.com/taek/p/6067652.html

你可能感兴趣的文章
STL-map
查看>>
第三周进度条
查看>>
Keil的lib生成个人总结
查看>>
java程序员常见面试题
查看>>
java @SuppressWarnings注解
查看>>
C语言位域
查看>>
Python量化教程 常用函数
查看>>
webpack笔记一 起步
查看>>
docker容器启动设置固定IP
查看>>
安装python爬虫scrapy踩过的那些坑(转载+整理)
查看>>
VC++ 的MFC 和ATL 及COM 是什么?
查看>>
MySQL Explain 总结
查看>>
ELK批量删除索引
查看>>
团队作业 团队组织方式讨论
查看>>
图片加载
查看>>
numpy学习小结
查看>>
ios单例模式-全局静态类
查看>>
我的世界2
查看>>
jquery_扩展
查看>>
Kubernetes Master节点灾备恢复操作指南---升级版
查看>>