我想创建一个函数formatFloat(),它接受任何浮动并将其格式化为十进制扩展字符串.例如:
formatFloat(1.0E+25);  // "10,000,000"
formatFloat(1.0E+24);  // "1,000"

formatFloat(1.000001);      // "1.000001"
formatFloat(1.000001E-10);  // "0.0000000001000001"
formatFloat(1.000001E-11);  // "0.00000000001000001"

初步想法

简单地说casting浮点到一个字符串将不起作用,因为对于大于约1.0E 14或小于约1.0E-4的浮点数,PHP在scientific notation而不是decimal expansion中呈现它们.

number_format()是一个明显的PHP函数.但是,大浮动会出现此问题:

number_format(1.0E+25);  // "10,905,969,664"
number_format(1.0E+24);  // "999,999,983,222,784"

对于小浮点数,难点在于选择要求的小数位数.一个想法是要求大量的十进制数字,然后rtrim()超过0.但是,这个想法是有缺陷的,因为十进制扩展通常不会以0结尾:

number_format(1.000001,30);  // "1.000000999999999917733362053696"
number_format(1.000001E-10,30);  // "0.000000000100000099999999996746"
number_format(1.000001E-11,30);  // "0.000000000010000010000000000321"

问题是浮点数具有limited precision,并且通常无法存储文字的确切值(例如:1.0E 25).相反,它存储可以表示的最接近的可能值. number_format()揭示了这些“最接近的近似值”.

Timo Frenay的解决方案

我在sprintf()页面深处埋没了this comment,令人惊讶的是没有upVotes:

Here is how to print a floating point number with 16 significant digits regardless of magnitude:

$result = sprintf(sprintf('%%.%dF',max(15 - floor(log10($value)),0)),$value);

关键部分是使用log10()来确定浮点数的order of magnitude,然后计算所需的小数位数.

有一些需要修复的错误:

>该代码不适用于负浮动.
>该代码不适用于极小的浮点数(例如:1.0E-100). PHP报告此通知:“sprintf():请求的116位数的精度被截断为PHP最多53位”
>如果$value为0.0,则log10($value)为-INF.
>由于PHP float的精度是“大约14位小数”,我认为应该显示14位有效数字而不是16位数.

我最好的尝试

这是我提出的最佳解决方案.它基于Timo Frenay的解决方案,修复了错误,并使用ThiefMaster’s regex修剪多余的0:

function formatFloat($value)
{
    if ($value == 0.0)  return '0.0';

    $decimalDigits = max(
        13 - floor(log10(abs($value))),0
    );

    $formatted = number_format($value,$decimalDigits);

    // Trim excess 0's
    $formatted = preg_replace('/(\.[0-9]+?)0*$/','$1',$formatted);

    return $formatted;
}

Here’s an Ideone demo有200个随机浮点数.代码似乎适用于小于约1.0E 15的所有浮点数.

有趣的是,即使是非常小的浮点数,number_format()也能正常工作:

formatFloat(1.000001E-250);  // "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000001"

这个问题

我对formatFloat()的最佳尝试仍然遇到这个问题:

formatFloat(1.0E+25);  // "10,664"
formatFloat(1.0E+24);  // "999,784"

有没有一种优雅的方法来改进代码来解决这个问题?

这段代码 seems to do the job too.我不认为我设法使它比你的更优雅,但我花了很多时间在它上面,我不能把它扔掉:)
function formatFloat(
    $value,$noOfDigits = 14,$separator = ',',$decimal = '.'
) {

    $exponent = floor(log10(abs($value)));
    $magnitude = pow(10,$exponent);

    // extract the significant digits
    $mantissa = (string)abs(round(($value /  pow(10,$exponent - $noOfDigits + 1))));
    $formattednum = '';

    if ($exponent >= 0) { // <=> if ($value >= 1)

        // just for pre-formatting
        $formattednum = number_format($value,$noOfDigits - 1,$decimal,$separator);

        // then report digits from $mantissa into $formattednum
        $formattedLen = strlen($formattednum);
        $mantissaLen = strlen($mantissa);
        for ($fnPos = 0,$mPos = 0; $fnPos <  $formattedLen; $fnPos++,$mPos++) {

            // skip non-digit
            while($formattednum[$fnPos] === $separator || $formattednum[$fnPos] === $decimal || $formattednum[$fnPos] === '-') {
                $fnPos++;
            }
            $formattednum[$fnPos] = $mPos < $mantissaLen ? $mantissa[$mPos] : '0';

        }

    } else { // <=> if ($value < 1)

        // prepend minus sign if necessary
        if ($value < 0) {
            $formattednum = '-';
        }
        $formattednum .= '0' . $decimal . str_repeat('0',abs($exponent) - 1) . $mantissa;

    }

    // strip trailing decimal zeroes
    $formattednum = preg_replace('/\.?0*$/','',$formattednum);

    return $formattednum;

}

PHP:将任何浮点数格式化为十进制扩展的更多相关文章

  1. xcode – Interface Builder的用户定义的运行时属性不接受浮点数?

    我创建了一个具有float属性的NSView子类,我想在InterfaceBuilder中设置它.在用户定义的运行时属性部分中,唯一合适的类型是数字.但是,如果我想输入一个十进制数,它只是舍入到最接近的整数.这是一个bug还是故意的?解决方法使用字符串类型并输入您的值

  2. 一 Swift学习之基础部分

    **一Swift学习之基础部分————–借鉴老码团队翻译组-Tyrion**//1.1常量和变量letsum=0//声明常量,值不可修改varnumber=1//声明变量,值可修改varx=0.0,y=1.0,z=2.0//在一行声明多个常量或变量用逗号隔开//1.2类型标注//声明常量或变量时可以加上类型标注,表示这个常量或变量存储的类型,但是如果你没有添加类型,而是赋了初始值,swift会自己推断类型letnum:Int=0varstr:String?Swift提供了两种有符号浮点数类型:Double

  3. Swift语法基础:8 - Swift的常量, 变量, 标注, 命名, 输出, 注释, 分号, 整数, 浮点数, 类型安全和类型推测说明

    Swift是一门新的语言,由于前期稳定性不够,所以导致会有一定的语法差异,有些人看到中文翻译过来的文档,和在Xcode里实现的不一样,就会各种找答案,找问题,我之所以会把我学习Swift遇到的问题共享出来,一方面是为了方便某人不愿意查看英文文档的朋友,另一方面就是为了给我自己做总结,是我在Xcode中一一试过,没有出现问题的我才会发出来,以后也会如此,直到Swift完全成熟稳定了,那我就以最后一个

  4. Swift语法基础:11 - Swift的运算术语, 赋值运算, 数值运算, 复合赋值

    在Swift当中当然是有与或非这三个逻辑运算符,并且兼容大部分C类运算符,比如“”,“=”,“==”,“=”,“+”,“-“,“*”,“/”,这些等等都支持,但这里有一点要注意一下,赋值符号“=”不返回值,以防止把“==”写成“=”导致程序出错.区别于C,Swfit还提供对浮点数类型进行取余预算“%”,还提供了C没有提供的区间,“0..

  5. Swift教程10-运算符与C语言的不同

    =,==这些运算符和其他语言的类似,是比较前后两个值是否相等,或者大小关系比较字符串内容是否相等,使用==即可但是Swift新增了===恒等于,是针对于引用类型,如两个对象之间是否是同一个对象与之对应的是!运算符示例Swift新增的??

  6. Swift学习:2.整型于浮点数

    整数整数范围你可以访问不同整数类型的min和max属性来获取对应类型的最大值和最小值:Int一般来说,你不需要专门指定整数的长度。Swift提供了一个特殊的整数类型Int,长度与当前平台的原生字长相同:在32位平台上,Int和Int32长度相同。浮点类型比整数类型表示的范围更大,可以存储比Int类型更大或者更小的数字。Swift提供了两种有符号浮点数类型:Double表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。Float表示32位浮点数。

  7. [翻译]Swift编程语言——基本操作符

    基本操作符操作符就是一个简单的符号或者短语,你可以用他们来检查、改变、组合数据。Swift支持标准C的大多数操作符而且有若干改进可以避免代码错误。算数运算符会检测并且不接受溢出的数据,你可以选用Swfit的溢出操作符预防这种情况出现。像C一样,Swift允许你对浮点数取余,同时Swfit也提供了两个C没有的范围操作符(a..术语操作符有一元、二元以及三元的:一元操作符只有一个操作对象(比如-a)。

  8. 【swift_1】swift基本语法及事例Demo

    语法类的文档网上比较多,我这里参考:Swift基本语法事例Demo:链接:http://pan.baidu.com/s/1jGCINCq密码:5mdk语法须知2个不需要不需要编写main函数:全局作用域中的代码会被自动当做程序的入口点(从上往下执行)不需要在每一条语句后面加上分号letradius=10你喜欢的话,也可以加上letradius=10;有一种情况必须加分号:同一行代码上有多条语句时1

  9. swift 基础笔记

  10. Swift数据类型(基础篇)

    swift可以自动识别变量类型,并进行赋值。但是请注意,尽量不要使用UInt,统一使用Int可以提高代码的可复用性,避免了不同类型数字的转换。

随机推荐

  1. PHP个人网站架设连环讲(一)

    先下一个OmnihttpdProffesinalV2.06,装上就有PHP4beta3可以用了。PHP4给我们带来一个简单的方法,就是使用SESSION(会话)级变量。但是如果不是PHP4又该怎么办?我们可以假设某人在15分钟以内对你的网页的请求都不属于一个新的人次,这样你可以做个计数的过程存在INC里,在每一个页面引用,访客第一次进入时将访问时间送到cookie里。以后每个页面被访问时都检查cookie上次访问时间值。

  2. PHP函数学习之PHP函数点评

    PHP函数使用说明,应用举例,精简点评,希望对您学习php有所帮助

  3. ecshop2.7.3 在php5.4下的各种错误问题处理

    将方法内的函数,分拆为2个部分。这个和gd库没有一点关系,是ecshop程序的问题。会出现这种问题,不外乎就是当前会员的session或者程序对cookie的处理存在漏洞。进过本地测试,includes\modules\integrates\ecshop.php这个整合自身会员的类中没有重写integrate.php中的check_cookie()方法导致,验证cookie时返回的username为空,丢失了登录状态,在ecshop.php中重写了此方法就可以了。把他加到ecshop.php的最后面去就可

  4. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  5. PHP使用JpGraph绘制折线图操作示例【附源码下载】

    这篇文章主要介绍了PHP使用JpGraph绘制折线图操作,结合实例形式分析了php使用JpGraph的相关操作技巧与注意事项,并附带源码供读者下载参考,需要的朋友可以参考下

  6. zen_cart实现支付前生成订单的方法

    这篇文章主要介绍了zen_cart实现支付前生成订单的方法,结合实例形式详细分析了zen_cart支付前生成订单的具体步骤与相关实现技巧,需要的朋友可以参考下

  7. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  8. PHP+jquery+CSS制作头像登录窗(仿QQ登陆)

    本篇文章介绍了PHP结合jQ和CSS制作头像登录窗(仿QQ登陆),实现了类似QQ的登陆界面,很有参考价值,有需要的朋友可以了解一下。

  9. 基于win2003虚拟机中apache服务器的访问

    下面小编就为大家带来一篇基于win2003虚拟机中apache服务器的访问。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. Yii2中组件的注册与创建方法

    这篇文章主要介绍了Yii2之组件的注册与创建的实现方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

返回
顶部