使用双精度幻数时的最佳做法 [英] Best practice when working with double precision magic numbers

查看:143
本文介绍了使用双精度幻数时的最佳做法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是否需要在所有 c>结尾处指定 D (例如, 1.234D + 00 如果我已经声明所有事情都是双精度的话,那么神奇数字(字面常量)就是一个href =https://en.wikipedia.org/wiki/Magic_number_%28programming%29 =nofollow noreferrer>

解决方案

简短的回答:是的,您确实如此。

:默认情况下,除非另有说明,否则实数文字是单精度的。将单精度文字分配给双精度变量会导致精度损失;也就是说,首先将单精度文字评估为单精度,然后将其分配给更高精度的变量。我懒得从其他房间检索F2003手册,但我怀疑单对分配将低显着性尾数位设置为零。无论如何,这是一个演示文字和变量之间混合精度时会发生什么(请注意0.1不能存储干净地用二进制浮点):

 !>演示D和E后缀对文字
程序的精确度的影响whatkind
use iso_fortran_env,only:output_unit,REAL32,REAL64
隐式无

真实(kind = REAL64):: dtest
$ b 10格式('Literal',A''是类型的',I2)
20格式(/,A)
30格式(/ '存储在''中的值'A''用',A和&
'精度字面值生成的精度:')
40格式('Literal is',A)

继续

write(output_unit,10)'1.0',kind(1.0)
write(output_unit,10)'1.0E0',kind(1.0E0)
write(output_unit ,10)'1.0D0',kind(1.0D0)
write(output_unit,10)'1.0_REAL32',kind(1.0_REAL32)
write(output_unit,10)'1.0_REAL64',kind( 1.0_REAL64)

write(output_unit,20)'原始十分之一测试:'

dtest = 0.1
write(output_unit,30)'double','single '
write(output_unit,40)'0.1'
write(output_unit,*)dtest

dtest = 0.1D0
write(output_unit,30)'double','double'
write(output_unit,40)'0.1 D0'
write(output_unit,*)dtest

dtest = 1.0 / 10.0
write(output_unit,30)'double','single'
write(output_unit ,40)'0.1'
write(output_unit,40)'1.0 / 10.0'
write(output_unit,*)dtest

dtest = 1.0_REAL64 / 10.0_REAL64
write(output_unit,30)'double','double'
write(output_unit,40)'1.0_REAL64 / 10.0_REAL64'
write(output_unit,*)dtest

dtest = 1.0_REAL32 / 10.0_REAL32
write(output_unit,30)'double','single'
write(output_unit,40)'1.0_REAL32 / 10.0_REAL32'
write(output_unit,* )dtest

dtest = 1.0_REAL64 / 10.0_REAL32
write(output_unit,30)'double','mixed'
write(output_unit,40)'1.0_REAL64 / 10.0_RE AL32'
write(output_unit,*)dtest

dtest = 1.0_REAL32 / 10.0_REAL64
write(output_unit,30)'double','mixed'
write (output_unit,40)'1.0_REAL32 / 10.0_REAL64'
write(output_unit,*)dtest

end program whatkind

结果如下:

  Literal 1.0是kind 4 
Literal 1.0E0类型4
Literal 1.0D0类型8
Literal 1.0_REAL32类型4
Literal 1.0_REAL64类型8

原始十分之一测试:

以单精度文字生成的以双精度存储的值:
Literal为0.1
0.10000000149011612

以双精度生成使用双精度字面值:
Literal为0.1D0
0.10000000000000001

以单精度字面值生成的双精度值存储:
立即数为0.1
立即数1.0 / 10.0
0.10000000149011 612

以双精度字面值生成的以双精度值存储的值:
Literal为1.0_REAL64 / 10.0_REAL64
0.10000000000000001

以双精度生成使用单精度字面值:
Literal为1.0_REAL32 / 10.0_REAL32
0.10000000149011612

以混合精度字面值生成的双精度值存储:
Literal为1.0_REAL64 / 10.0 _REAL32
0.10000000000000001

以混合精度文字生成的双精度值存储的值:
Literal是1.0_REAL32 / 10.0_REAL64
0.10000000000000001


我发现有趣的是对混合精度文字的操作似乎将所有文字提升到更高精度在执行操作之前进行。有更多language-spec-fu的人可能会解释这一点。



我的建议:如有疑问,请明确表示。它更安全,我认为这是值得的额外击键。


Do I necessarily need to specify D (e.g., 1.234D+00) at the end of all magic numbers (literal constants) if I've already declared everything double precision anyway?

解决方案

Short answer: Yes, you do.

Long answer: By default, real literals are single precision unless otherwise specified. Assigning single precision literals to double precision variables incurs precision loss; that is, single precision literals are evaluated first as single precision then assigned to the higher-precision variable. I'm too lazy to retrieve the F2003 Handbook from the other room but I suspect that single-to-double assignment sets the low significance mantissa bits to zero. Either that or it's left up to the vendor.

Regardless, here's a demonstration of what happens when you mix precision between literals and variables (note that 0.1 can't be stored cleanly in binary floating point):

!> Demonstrate the effects of D and E suffixes on precision of literals
program whatkind
    use iso_fortran_env, only: output_unit, REAL32, REAL64
    implicit none

    real (kind=REAL64) :: dtest

10 format('Literal ', A, ' is of kind ', I2)
20 format(/, A)
30 format(/, 'Value stored in ', A, ' precision generated with ', A,    &
          ' precision literals:')
40 format('Literal is ', A)

    continue

    write(output_unit, 10) '1.0', kind(1.0)
    write(output_unit, 10) '1.0E0', kind(1.0E0)
    write(output_unit, 10) '1.0D0', kind(1.0D0)
    write(output_unit, 10) '1.0_REAL32', kind(1.0_REAL32)
    write(output_unit, 10) '1.0_REAL64', kind(1.0_REAL64)

    write(output_unit, 20) 'Raw tenths tests:'

    dtest = 0.1
    write(output_unit, 30) 'double', 'single'
    write(output_unit, 40) '0.1'
    write(output_unit, *) dtest

    dtest = 0.1D0
    write(output_unit, 30) 'double', 'double'
    write(output_unit, 40) '0.1D0'
    write(output_unit, *) dtest

    dtest = 1.0 / 10.0
    write(output_unit, 30) 'double', 'single'
    write(output_unit, 40) '0.1'
    write(output_unit, 40) '1.0 / 10.0'
    write(output_unit, *) dtest

    dtest = 1.0_REAL64 / 10.0_REAL64
    write(output_unit, 30) 'double', 'double'
    write(output_unit, 40) '1.0_REAL64 / 10.0_REAL64'
    write(output_unit, *) dtest

    dtest = 1.0_REAL32 / 10.0_REAL32
    write(output_unit, 30) 'double', 'single'
    write(output_unit, 40) '1.0_REAL32 / 10.0_REAL32'
    write(output_unit, *) dtest

    dtest = 1.0_REAL64 / 10.0_REAL32
    write(output_unit, 30) 'double', 'mixed'
    write(output_unit, 40) '1.0_REAL64 / 10.0_REAL32'
    write(output_unit, *) dtest

    dtest = 1.0_REAL32 / 10.0_REAL64
    write(output_unit, 30) 'double', 'mixed'
    write(output_unit, 40) '1.0_REAL32 / 10.0_REAL64'
    write(output_unit, *) dtest

end program whatkind

The results of this are:

Literal 1.0 is of kind  4
Literal 1.0E0 is of kind  4
Literal 1.0D0 is of kind  8
Literal 1.0_REAL32 is of kind  4
Literal 1.0_REAL64 is of kind  8

Raw tenths tests:

Value stored in double precision generated with single precision literals:
Literal is 0.1
  0.10000000149011612     

Value stored in double precision generated with double precision literals:
Literal is 0.1D0
  0.10000000000000001     

Value stored in double precision generated with single precision literals:
Literal is 0.1
Literal is 1.0 / 10.0
  0.10000000149011612     

Value stored in double precision generated with double precision literals:
Literal is 1.0_REAL64 / 10.0_REAL64
  0.10000000000000001     

Value stored in double precision generated with single precision literals:
Literal is 1.0_REAL32 / 10.0_REAL32
  0.10000000149011612     

Value stored in double precision generated with mixed precision literals:
Literal is 1.0_REAL64 / 10.0_REAL32
  0.10000000000000001     

Value stored in double precision generated with mixed precision literals:
Literal is 1.0_REAL32 / 10.0_REAL64
  0.10000000000000001 

You see how in cases where all the literals are single precision (including those with no explicit precision set) there is low significance 'noise' stored in the double precision variable.

I find it interesting that operations on mixed precision literals seems to promote all the literals to higher precision before the operation is performed. Someone with more language-spec-fu might be able to explain that.

My advice: When in doubt, be explicit. It's safer and I think it's worth the extra keystrokes.

这篇关于使用双精度幻数时的最佳做法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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