[英]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.