32193


OSSのコードを見ているとたまに浮動小数点の値に下記のような

[code]

    float f = 1.f;
    double d = 1.;
    
[/code]

少数部分を書かない記法を見かけます。これは1.0f, 1.0と書く場合と比べて何か違いがあるのでしょうか？  
こういう書き方の時は、あれこれというニュアンスを含むことが多い、といった回答でもOKです。


CC BY-SA 3.0
2017-01-26T07:45:05.267
32168
2017-01-27T23:49:49.640
17238
question
c++ c
C/C++のfloatの1.0と1.の違い


以下のような簡単なプログラムを用意してそれぞれアセンブルして出力してみました。  
結果として違いは出なかったため、どちらの書き方でも言語仕様としての差異はないでしょう。  
(もっと複雑なコードや、コンパイラによっては違いが出るのかもしれませんが、もっと詳しい方が補足されると信じます)  
コメントでも書かれているように、コーディング規約としてどうするか、といった問題だと思います。

test1.c

[code]

    #include <stdio.h>
    
    int main() {
        float f = 1.f;
        double d = 1.;
    
        printf("%f, %lf", f, d);
    
        return 0;
    }
    
[/code]

test2.c

[code]

    #include <stdio.h>
    
    int main() {
        float f = 1.0f;
        double d = 1.0;
    
        printf("%f, %lf", f, d);
    
        return 0;
    }
    
[/code]

アセンブル後はどちらも以下のようになる

[code]

        .section    __TEXT,__text,regular,pure_instructions
        .macosx_version_min 10, 11
        .section    __TEXT,__literal8,8byte_literals
        .align  3
    LCPI0_0:
        .quad   4607182418800017408     ## double 1
        .section    __TEXT,__literal4,4byte_literals
        .align  2
    LCPI0_1:
        .long   1065353216              ## float 1
        .section    __TEXT,__text,regular,pure_instructions
        .globl  _main
        .align  4, 0x90
    _main:                                  ## @main
        .cfi_startproc
    ## BB#0:
        pushq   %rbp
    Ltmp0:
        .cfi_def_cfa_offset 16
    Ltmp1:
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
    Ltmp2:
        .cfi_def_cfa_register %rbp
        subq    $32, %rsp
        leaq    L_.str(%rip), %rdi
        movsd   LCPI0_0(%rip), %xmm0    ## xmm0 = mem[0],zero
        movss   LCPI0_1(%rip), %xmm1    ## xmm1 = mem[0],zero,zero,zero
        movl    $0, -4(%rbp)
        movss   %xmm1, -8(%rbp)
        movsd   %xmm0, -16(%rbp)
        cvtss2sd    -8(%rbp), %xmm0
        movsd   -16(%rbp), %xmm1        ## xmm1 = mem[0],zero
        movb    $2, %al
        callq   _printf
        xorl    %ecx, %ecx
        movl    %eax, -20(%rbp)         ## 4-byte Spill
        movl    %ecx, %eax
        addq    $32, %rsp
        popq    %rbp
        retq
        .cfi_endproc
    
        .section    __TEXT,__cstring,cstring_literals
    L_.str:                                 ## @.str
        .asciz  "%f, %lf"
    
    
    .subsections_via_symbols
    
[/code]

* * *

コンパイラ  
Apple LLVM version 8.0.0 (clang-800.0.42.1)


CC BY-SA 3.0
2017-01-27T04:41:34.063
32186
2017-01-27T04:41:34.063
20272
32168
answer


C/C++コンパイラから見れば `1.0` および `1.` ともに、構文要素としては C: 浮動小数点定数( _floating-constant_ )
/ C++: 浮動小数点リテラル( _floating-literal_ ) です。両者は全く同じものとして扱われます。

プログラマ視点としては、下記いずれかではないでしょうか：

  * 浮動小数点数であることは明記したいが、小数部以下がゼロのため省略。
  * 有効数字（有効桁数）を表現する。`1.0`なら2桁／`1.`なら1桁。


CC BY-SA 3.0
2017-01-27T07:19:02.893
32193
2017-01-27T07:24:43.600
2017-01-27T07:24:43.600
49
49
32168
answer


C11規格書のドラフト([N1570](http://www.open-
std.org/jtc1/sc22/wg14/www/docs/n1570.pdf))を調べてみました。

6.4.4.2 Floating constants (N1570 p.66) より

> 5 Floating constants are converted to internal format as if at translation-
> time. The conversion of a floating constant shall not raise an exceptional
> condition or a floating- point exception at execution time. All floating
> constants of the same source form75) shall convert to the same internal
> format with the same value.
>
> 75) 1.23, 1.230, 123e-2, 123e-02, and 1.23L are all different source forms
> and thus need not convert to the same internal format and value.

この記述によれば、同じソース形式であれば同じ内部フォーマットである必要はありますが、異なるソース形式の場合は、同じ内部フォーマット、同じ内部値である必要は無いとのことです。よって、
**`1.0`と`1.`が必ず同じになるとは限らない可能性があります。**

しかし、その後のRecommended practice(推奨される方法)として、次のように書かれています。

> 7 The translation-time conversion of floating constants should match the
> execution-time conversion of character strings by library functions, such as
> strtod, given matching inputs suitable for both conversions, the same result
> format, and default execution-time rounding.76)
>
> 76) The specification for the library functions recommends more accurate
> conversion than required for floating constants (see 7.22.1.3).

`strtod`などと同じように動作するとあります。`strtod`では丸め誤差等の方法をどのようにするのかが厳密に定義されており、有効桁数範囲内の10進数表記で同じ数字は必ず等値と扱われるようになっています。そのため、実際の演算では、どんな内部フォーマットを使われているかは影響が無いと思われます。

※ 浮動小数点数が等値かどうかの判断は単純なビット列の一致では **ありません** 。ビット列が異なっていても等値と判断される場合があります。

現実的な話をすると、ほとんどの実装では浮動小数点数をIEEE 754のbinary32(単精度)とbinary64(倍精度)で実装しています。IEEE
754に基づいた変換では内部フォーマットに違いが出ることは無いと思われます。(ここら辺はIEEE 754にそこまで詳しくないのであやしいです)

※ IEEE 754のbinary32とbinary64は、Cの仕様上のfloatとdouble、および、long
doubleの要件を満たしますが、それらを使用しなければならないという逆の要件はありません。Cでは2進数以外での実装した場合の動作も定めています。(JavaやECMAScriptにはIEEE
754のbinary32やbinary64でなければならないという要件がありますが、Rubyなど実装依存(ほとんどの場合はCでの実装)とする言語も多いようです。)

ビット列に違いが出るかどうかはunionで無理矢理調べることができると思います。

[code]

    #include <assert.h>
    #include <inttypes.h>
    #include <stdint.h>
    #include <stdio.h>
    
    union dd {
        double d;
        uint64_t u;
    };
    
    int main(void)
    {
        assert(sizeof(double) == sizeof(uint64_t));
        union dd x = {.d = 1.0};
        union dd y = {.d = 1.};
        printf("%016" PRIX64 " : %016" PRIX64 "\n", x.u, y.u);
        return 0;
    }
    
[/code]

C++については、N3242をさらっと見た限り、正しくスケーリングを行うことしか書いて無く、上記のような記述は見られませんでした。


CC BY-SA 3.0
2017-01-27T23:49:49.640
32211
2017-01-27T23:49:49.640
7347
32168
answer