Java 中 C 的 printf %g 格式说明符的等价物是什么?

发布于 2024-07-19 07:46:03 字数 711 浏览 11 评论 0原文

我尝试使用 Formatter.format,但这似乎将尾数留在尾数为 0 的数字上,而 C 版本却没有。 Java 中是否有相当于 C 的 %g 格式说明符,如果没有,是否有办法伪造它? 出于兼容性原因,我的目的是像 C 那样保留尾数。

foo.c

#include <stdio.h>

int main (int argc, char const *argv[])
{
    printf("%g\n", 1.0);
    return 0;
}

Main.java

class Main {
        public static void main(String[] args) {
                System.out.printf("%g\n", 1.0);
        }
}

控制台:

$ javac Main.java && java Main
1.00000
$ gcc foo.c && ./a.out
1

同样,以 1.2 作为输入,Java 版本中的尾数更长

$ javac Main.java && java Main
1.20000
$ gcc foo.c && ./a.out
1.2

I tried using Formatter.format, but that seems to leave the mantissa on numbers with 0 mantissa, whereas the C version does not. Is there an equivalent of C's %g format specifier in Java, and if not, is there a way to fake it? My intention is to preserve the mantissa exactly like C's for compatibility reasons.

foo.c

#include <stdio.h>

int main (int argc, char const *argv[])
{
    printf("%g\n", 1.0);
    return 0;
}

Main.java

class Main {
        public static void main(String[] args) {
                System.out.printf("%g\n", 1.0);
        }
}

Console:

$ javac Main.java && java Main
1.00000
$ gcc foo.c && ./a.out
1

Similarly, with 1.2 as input, the mantissa is longer in Java's version

$ javac Main.java && java Main
1.20000
$ gcc foo.c && ./a.out
1.2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

瀞厅☆埖开 2024-07-26 07:46:03

编辑
如果指数是 17 位数字,此代码会导致小数部分丢失,因为我误解了 String.format 如何格式化这些数字。 所以请不要使用此代码:P

感谢您的输入,伙计们。 我找不到配置 DecimalFormat 或 NumberFormat 来精确克隆功能的方法,但似乎此方法有效(后面是一个示例):

String.format("%.17g", x).replaceFirst("\\.?0+(e|$)", "$1");

main.c

#include <stdio.h>

int main (int argc, char const *argv[])
{
    printf("%.*g\n", 17, -0.0);
    printf("%.*g\n", 17, 0.0);
    printf("%.*g\n", 17, 1.0);
    printf("%.*g\n", 17, 1.2);
    printf("%.*g\n", 17, 0.0000000123456789);
    printf("%.*g\n", 17, 1234567890000000.0);
    printf("%.*g\n", 17, 0.0000000123456789012345678);
    printf("%.*g\n", 17, 1234567890123456780000000.0);
    return 0;
}

Main.java

class Main {
        public static String formatDouble(double x) {
                return String.format("%.17g", x).replaceFirst("\\.?0+(e|$)", "$1");
        }

        public static void main(String[] args) {
                System.out.println(formatDouble(-0.0));
                System.out.println(formatDouble(0.0));
                System.out.println(formatDouble(1.0));
                System.out.println(formatDouble(1.2));
                System.out.println(formatDouble(0.0000000123456789));
                System.out.println(formatDouble(1234567890000000.0));
                System.out.println(formatDouble(0.0000000123456789012345678));
                System.out.println(formatDouble(1234567890123456780000000.0));
        }
}

及其输出:

$ gcc foo.c && ./a.out
-0
0
1
1.2
1.23456789e-08
1234567890000000
1.2345678901234567e-08
1.2345678901234568e+24
$ javac Main.java && java Main
-0
0
1
1.2
1.23456789e-08
1234567890000000
1.2345678901234567e-08
1.2345678901234568e+24

edit:
This code causes the fractional part to go missing if the exponent is 17 digits, because of my misunderstanding of how String.format formatted those numbers. So don't please don't use this code :P

Thanks for the input, guys. I couldn't find a way to configure DecimalFormat or NumberFormat to exactly clone the functionality, but it seems this method works (followed by an example):

String.format("%.17g", x).replaceFirst("\\.?0+(e|$)", "$1");

main.c

#include <stdio.h>

int main (int argc, char const *argv[])
{
    printf("%.*g\n", 17, -0.0);
    printf("%.*g\n", 17, 0.0);
    printf("%.*g\n", 17, 1.0);
    printf("%.*g\n", 17, 1.2);
    printf("%.*g\n", 17, 0.0000000123456789);
    printf("%.*g\n", 17, 1234567890000000.0);
    printf("%.*g\n", 17, 0.0000000123456789012345678);
    printf("%.*g\n", 17, 1234567890123456780000000.0);
    return 0;
}

Main.java

class Main {
        public static String formatDouble(double x) {
                return String.format("%.17g", x).replaceFirst("\\.?0+(e|$)", "$1");
        }

        public static void main(String[] args) {
                System.out.println(formatDouble(-0.0));
                System.out.println(formatDouble(0.0));
                System.out.println(formatDouble(1.0));
                System.out.println(formatDouble(1.2));
                System.out.println(formatDouble(0.0000000123456789));
                System.out.println(formatDouble(1234567890000000.0));
                System.out.println(formatDouble(0.0000000123456789012345678));
                System.out.println(formatDouble(1234567890123456780000000.0));
        }
}

and their outputs:

$ gcc foo.c && ./a.out
-0
0
1
1.2
1.23456789e-08
1234567890000000
1.2345678901234567e-08
1.2345678901234568e+24
$ javac Main.java && java Main
-0
0
1
1.2
1.23456789e-08
1234567890000000
1.2345678901234567e-08
1.2345678901234568e+24
乱世争霸 2024-07-26 07:46:03

您是否尝试过 java.text.DecimalFormat 类?

System.out.println(new DecimalFormat().format(1.0));

输出:

1

而:

System.out.println(new DecimalFormat().format(1.2));

输出:

1.2

Have you tried the java.text.DecimalFormat class?

System.out.println(new DecimalFormat().format(1.0));

outputs:

1

whereas:

System.out.println(new DecimalFormat().format(1.2));

outputs:

1.2
时光礼记 2024-07-26 07:46:03

您可以使用 NumberFormat。 通过将最小小数位数设置为 0,但将最大小数位数设置得更大,它应该可以满足您的要求。

它不像 printf 那么容易,但它应该可以工作。

You could use a NumberFormat. By setting the minimum fraction digits to 0, but leaving the maximum bigger, it should do what you want.

It's not as easy as printf, but it should work.

じее 2024-07-26 07:46:03

好吧,您可以指定所需的位数:“%.2g”会将 1.2 显示为 1.20

well, you can specify how many digits you want: "%.2g" will display 1.2 as 1.20

囍孤女 2024-07-26 07:46:03

请注意,对于 1.2345e-20,使用

String.format("%.17g", x).replaceFirst("\\.?0+(e|$)", "$1")

失败(从末尾去除零,生成 1.2345e-2)。
这是我最终在代码中使用的内容:

String.format(Locale.US, "%.6g", x).replaceFirst("\\.0+(e|$)", "$1").replaceFirst("(\\.[0-9]*[1-9])(0+)(e|$)", "$1$3")

基本上,我修改了表达式以确保仅删除小数部分末尾的零,并将其分为两种情况。 但感谢您为我指明了正确的方向。

Note that using

String.format("%.17g", x).replaceFirst("\\.?0+(e|$)", "$1")

fails for 1.2345e-20 (strips the zero from the end, producing 1.2345e-2).
Here is what I ended up using in my code:

String.format(Locale.US, "%.6g", x).replaceFirst("\\.0+(e|$)", "$1").replaceFirst("(\\.[0-9]*[1-9])(0+)(e|$)", "$1$3")

Basically I modified the expression to ensure only zeros at the end of the fractional part are removed and split this into two cases. But thanks for pointing me in the right direction.

停滞 2024-07-26 07:46:03

上述解决方案都不是完美的。 在某些情况下,到处都会出现很多问题。 因此,我创建了一个小型库 Double2String 来解决这个特定问题:

https://github.com/coconut2015/double2string

None of the above solutions are prefect. There are quite a few issues here and there in certain cases. So I created a small library Double2String to address this specific issue:

https://github.com/coconut2015/double2string

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文