了解Python %g 在字符串格式化中的实现,实现Java String.format 行为 [英] Understanding the Python %g in string formatting, achieving Java String.format behavior

查看:70
本文介绍了了解Python %g 在字符串格式化中的实现,实现Java String.format 行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Java 中:

String test1 = String.format("%7.2g", 3e9);System.out.println(test1);

这会打印3.0e+09

在 Python 2.7 中,如果我运行此代码

 for num in [3e9, 3.1e9, 3.01e9, 3e2, 3.1e2, 3.01e2]:打印 '%7.2g %7.2f %7.2e' % (num, num, num)

我明白

 3e+09 3000000000.00 3.00e+093.1e+09 3100000000.00 3.10e+093e+09 3010000000.00 3.01e+093e+02 300.00 3.00e+023.1e+02 310.00 3.10e+023e+02 301.00 3.01e+02

嗯?看起来精度 (.2) 参数在 Python 的 %g 中的处理方式与 Python 的 %f、Python 的 %e 或Java 的 %g.这是doc(我的重点):

<块引用>

通用格式.对于给定的精度 p >= 1,这会将数字四舍五入为 p 个有效数字,然后根据其大小将结果格式化为定点格式或科学记数法.

精确规则如下:假设以表示类型'e'和精度p-1格式化的结果将具有指数exp.那么如果 -4 <= exp <p,数字的格式为表示类型f",精度为 p-1-exp.否则,数字的格式为表示类型e"和精度 p-1.在这两种情况下,从有效数中删除无关紧要的尾随零,如果小数点后面没有剩余数字,也会删除小数点.

无论精度如何,正负无穷大、正负零和 nans 的格式分别为 inf、-inf、0、-0 和 nan.

精度为 0 被视为等同于精度 1.默认精度为 6.

WTF?有没有办法防止那些尾随零被删除?字符串格式化的重点是实现一些一致性,例如用于文本对齐.

有没有什么方法可以让 Java 行为(本质上是小数点右边的有效数字的数量)而不必从头开始重写整个事情?

解决方案

python 所做的格式更符合 C 的 printf 样式格式,它还删除 g 转换的尾随零.既然python的参考实现是用C写的,那么为什么要和Java保持一致呢?

当使用 % 运算符进行字符串格式化时,相关文档为 字符串格式化操作,它与您链接的操作有一些不同,特别是它允许 # 替代 g:

<块引用>

替代形式导致结果始终包含小数点,并且不会像其他情况那样删除尾随零.

精度决定小数点前后有效位数,默认6位.

所以在你的情况下:

<预><代码>>>>"%#7.2g" % 3e93.0e+09

这与 str.format() 允许的不同,其中 # 用于启用二进制、八进制或十六进制输出的前缀(至少在 python2,这是在python3中改变的).

In Java:

String test1 = String.format("%7.2g", 3e9);
System.out.println(test1);

This prints 3.0e+09

In Python 2.7, if I run this code

for num in [3e9, 3.1e9, 3.01e9, 3e2, 3.1e2, 3.01e2]:
   print '%7.2g %7.2f %7.2e' % (num, num, num)

I get

  3e+09 3000000000.00 3.00e+09
3.1e+09 3100000000.00 3.10e+09
  3e+09 3010000000.00 3.01e+09
  3e+02  300.00 3.00e+02
3.1e+02  310.00 3.10e+02
  3e+02  301.00 3.01e+02

Huh? It looks like the precision (.2) argument is treated totally differently in Python's %g than in Python's %f, Python's %e, or Java's %g. Here's the doc (my emphasis):

General format. For a given precision p >= 1, this rounds the number to p significant digits and then formats the result in either fixed-point format or in scientific notation, depending on its magnitude.

The precise rules are as follows: suppose that the result formatted with presentation type 'e' and precision p-1 would have exponent exp. Then if -4 <= exp < p, the number is formatted with presentation type 'f' and precision p-1-exp. Otherwise, the number is formatted with presentation type 'e' and precision p-1. In both cases insignificant trailing zeros are removed from the significand, and the decimal point is also removed if there are no remaining digits following it.

Positive and negative infinity, positive and negative zero, and nans, are formatted as inf, -inf, 0, -0 and nan respectively, regardless of the precision.

A precision of 0 is treated as equivalent to a precision of 1. The default precision is 6.

WTF? Is there any way to prevent those trailing zeros from being removed? The whole point of string formatting is to achieve some consistency, e.g. for text alignment.

Is there any way to get the Java behavior (essentially the number of significant digits to the right of the decimal point) without having to rewrite the whole thing from scratch?

解决方案

The formatting that python does is more consistent with C's printf style formatting, which also drops trailing zeros for the g conversion. Since python's reference implementation is in C, why should it be consistent with Java in this case?

When using the % operator for string formatting, the relevant documentation is String Formatting Operations, which has some differences to the one you linked to, notably that it allows the # alternate form for g:

The alternate form causes the result to always contain a decimal point, and trailing zeroes are not removed as they would otherwise be.

The precision determines the number of significant digits before and after the decimal point and defaults to 6.

So in your case:

>>> "%#7.2g" % 3e9
3.0e+09

This is different from what is allowed by str.format(), where # is used to enable prefixes for binary, octal or hexadecimal output (at least in python2, this was changed in python3).

这篇关于了解Python %g 在字符串格式化中的实现,实现Java String.format 行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆