简体   繁体   English

fortran中的十六进制浮点

[英]Hexadecimal floating point in fortran

Is there an equivalent for the 'a' format specifier known from C in Fortran? Fortran中C已知的'a'格式说明符是否等效?

C Example: C示例:

printf("%a\n",43.1e6); // 0x1.48d3bp+25

Exporting floating point numbers in hexadecimal format prevents rounding errors. 以十六进制格式导出浮点数可防止舍入错误。 While the rounding errors are usually negligible, it is still advantageous to be able to restore a saved value exactly. 虽然舍入误差通常可以忽略不计,但是仍然能够精确地恢复保存的值仍然是有利的。 Note, that the hexadecimal representation produced by printf is portable and human readable. 请注意,printf生成的十六进制表示形式是可移植的,并且易于阅读。

How can I export and parse floating point numbers in Fortran like I do in C using the 'a' specifier? 如何像使用C一样在C语言中导出和解析Fortran中的浮点数?

If you want to have full precision, the best way is to use unformatted files, such as this: 如果要完全精确,最好的方法是使用未格式化的文件,例如:

program main
  real :: r
  integer :: i
  r = -4*atan(1.)
  open(20,access="stream")
  write (20) r
  close(20)
end program main

(I used stream access, which is new to Fortran 2003, because it is usually less confusing than normal unformatted access). (我使用了Fortran 2003新增的流访问,因为它通常比普通的无格式访问更容易混淆)。 You can then use, for example, od -t x1 fort.20 to look at this as a hex dump. 然后,您可以使用od -t x1 fort.20将其视为十六进制转储。

You can also use TRANSFER to copy the bit pattern to an integer and then use the Z edit descriptor. 您也可以使用TRANSFER将位模式复制到整数,然后使用Z编辑描述符。

If you really want to mimic the %a specifier, you'll have to roll your own. 如果您真的想模仿%a指示符,则必须自己动手。 Most machines now use IEEE format. 现在,大多数机器都使用IEEE格式。 Use TRANSFER for copying the pattern to an integer, then pick that apart using IAND (and multiplications or divisions by powers of two for shifting). 使用TRANSFER将模式复制到整数,然后使用IAND (以及乘或除以2的幂进行移位)将其分开。

Another option would be to let the C library do your work for you and interface via C binding. 另一种选择是让C库为您完成工作并通过C绑定进行接口。 This rather depends on a modern compiler (some F2003 features used). 而是取决于现代编译器(使用了某些F2003功能)。

module x
  use, intrinsic :: iso_c_binding
  private
  public :: a_fmt
  interface
     subroutine doit(a, dest, n) bind(C) 
       import
       real(kind=c_double), value :: a
       character(kind=c_char), intent(out) :: dest(*)
       integer, value :: n
     end subroutine doit
  end interface

  interface a_fmt
     module procedure a_fmt_float, a_fmt_double
  end interface a_fmt

contains
  function a_fmt_float(a) result(res)
    real(kind=c_float), intent(in) :: a
    character(len=:), allocatable :: res
    res = a_fmt_double (real(a, kind=c_double))
  end function a_fmt_float

  function a_fmt_double(a) result(res)
    real(kind=c_double), intent(in) :: a
    character(len=:), allocatable :: res
    character(len=30) :: dest
    integer :: n
    call doit (a, dest, len(dest))
    n = index(dest, achar(0))
    res = dest(1:n)
  end function a_fmt_double

end module x

program main
  use x
  implicit none
  double precision :: r
  integer :: i
  r = -1./3.d0
  do i=1,1030
     print *,a_fmt(r)
     r = - r * 2.0
  end do
end program main

#include <stdio.h>

void doit (double a, char *dest, int n)
{
  snprintf(dest, n-1, "%a", a);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM