V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
nealot
V2EX  ›  程序员

C/C++ 下完全复刻 Python print("%s", floatnum) 好像有点难

  •  
  •   nealot · 275 天前 · 1540 次点击
    这是一个创建于 275 天前的主题,其中的信息可能已经有所发展或是发生改变。
    $ cat test.c
    #include <stdio.h>
    
    void main()
    {
        double v = 1.38;
        printf("%lf\n", v);
        printf("%.17g\n", v);
    }
    
    $ gcc test.c -o test
    $ ./test
    1.380000
    1.3799999999999999
    
    $ python3
    Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> v = 1.38
    >>> print("%s" % v)
    1.38
    

    需求很简单:我要在 C/C++ 中打印浮点数时,像 Python "%s" % v 那样打印,只打印必要的小数点后内容

    Stack Overflow 上有一篇讨论

    https://stackoverflow.com/questions/16839658/printf-width-specifier-to-maintain-precision-of-floating-point-value

    建议使用 printf("%.17g", number) 但是测试后发现它不工作

    简单翻了一些资料,似乎 %.17g 的数字要达到 17 确实是有必要的

    (我的系统是 Ubuntu 22.04 / x86_64)

    8 条回复    2024-02-20 23:05:25 +08:00
    aiqinxuancai
        1
    aiqinxuancai  
       275 天前
    c++20 的 std::format
    cwxiaos
        2
    cwxiaos  
       275 天前 via iPhone
    有 Python-like 的 print 库的

    https://ufile.io/lp2v1gb8
    cwxiaos
        3
    cwxiaos  
       275 天前   ❤️ 1
    ```
    #include <stdio.h>
    #include "print.h"

    int main(int argc, char** agrv){
    float num_1 = 1.38;
    int num_2 = 1;
    double num_3 = 3.22230001;
    print("Num1:", num_1, "Num2:", num_2, "Num3:", num_3);

    return 0;
    }
    ```

    Debian 12 /x86_64 下:

    ```
    Num1: 1.38 Num2: 1 Num3: 3.2223
    ```

    在 C++下用 C++的 API, C 下面也可以使用%g

    ```
    #include <stdio.h>
    #include "print.h"

    int main(int argc, char** agrv){
    float num = 1.38;
    printf("%g\n", num);

    return 0;
    }
    ```

    打印

    ```
    1.38
    ```
    nealot
        4
    nealot  
    OP
       275 天前
    %g 应该是正解

    stackoverflow 上票数第二高的答案,煞有介事地介绍要用 %.17g ...

    %.17g 确实达到了 double 地精度上界了,而且其实 %.17g 在不少情况下工作是正常的,估计 stackoverflow 上的回答者没有仔细测试就把方案发出来了
    cwxiaos
        5
    cwxiaos  
       275 天前 via iPhone
    @nealot %g 不是,我试了下,数字大了会跳成科学计数法,还是用现成库吧
    cwxiaos
        7
    cwxiaos  
       275 天前
    %.15g 可以,这个应该和浮点误差有关,1.38 恰好在 17 位有个 1,所以打了出来
    ```
    double num1 = 123.456;
    double num2 = 78.9;
    double num3 = 12345.6789;
    double num4 = 1.38;
    ```

    输出

    ```
    123.456
    78.9
    12345.6789
    1.38
    ```

    合理选择位数,避免浮点误差导致的多出来的数就行了
    cnbatch
        8
    cnbatch  
       275 天前
    如果你的编译器支持 C++20 ,用内置的 format 即可:
    https://coliru.stacked-crooked.com/a/56cb3388b1c85629

    ```
    #include <format>
    #include <iostream>


    int main()
    {
    double v = 1.38;
    std::cout << std::format("{}\n", v);
    }
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   948 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 21:29 · PVG 05:29 · LAX 13:29 · JFK 16:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.