I came up with the idea of implementing an effective function that converts floating point numbers to decimal strings without using internal IO when discussing the disp function. And recently I have tried to work it out.
The original Ryu can generate the shortest precision-preserving string of a floating point number and Ryu printf provides formatting of floating point numbers.
Based on the C and Scala version of Ryu codes, I have implemented the Fortran version of Ryu.
I think we can replace the current implementation in stdlib with Ryu-based codes. So I would like to briefly describe the API of ryu_fortran.
Currently, ryu_fortran provides four routines: f2shortest, d2shortest, d2fixed and d2exp.
use ryu, only: f2shortest, d2shortest, d2fixed, d2exp
use iso_fortran_env, only: real32, real64
write (*, "(A)") f2shortest(3.14159_real32)
write (*, "(A)") d2shortest(2.718281828_real64)
write (*, "(A)") d2fixed(1.2345678987654321_real64, 10)
write (*, "(A)") d2exp(299792458._real64, 5)
! 3.14159
! 2.718281828
! 1.2345678988
! 2.99792E+08
Interface
interface
function f2shortest(f) result(str)
real(kind=real32), intent(in) :: f
character(len=:), allocatable :: str
end function
function d2shortest(d) result(str)
real(kind=real64), intent(in) :: d
character(len=:), allocatable :: str
end function
function d2fixed(d, precision_) result(str)
real(kind=real64), intent(in) :: d
integer(kind=int32), intent(in) :: precision_
character(len=:), allocatable :: str
end function
function d2exp(d, precision_) result(str)
real(kind=real64), intent(in) :: d
integer(kind=int32), intent(in) :: precision_
character(len=:), allocatable :: str
end function
end interface
f2shortest and d2shortest produce shortest precision-preserving decimal strings of floating point numbers, that is, if we convert strings back to floating point values, we should get same binary representation comparing to original numbers. These two routines are suitable for cases where format is not specified. Note: f2shortest and d2shortest always print at least two digits. For example, C version of Ryu produces "1" for 1._real32 while f2shortest produces "1.0".
d2fixed and d2exp do formatting for real64 floating point numbers. The main difference between them and Fortran edit descriptors is that they don't produce "*****".
With these routines, I wrote a simple prototype of to_string for floating point numbers in app/main.f90. For stdlib, I think when format argument is not presented, f2shortest and d2shortest can be called. But when format is specified, there might be a disagreement over whether we follow Fortran convention or not. The good points of Ryu formatting are fast and that it never produces "*****". But it can not control the width of formatted values, which is sometimes required.
I hope in this issue we can discuss the above points and reach certain agreements.
P.S. Benchmark results (edited on 2022.2.9)
Benchmark for f2shortest
f2shortest Time (us): 0.2019531 Std Dev: 0.3438
internal IO Time (us): 1.6445312 Std Dev: 0.3450
Benchmark for d2shortest
d2shortest Time (us): 0.2128906 Std Dev: 0.3496
internal IO Time (us): 2.1968750 Std Dev: 0.4361
Benchmark for d2exp
d2exp Time (us): 0.2976563 Std Dev: 0.3794
internal IO Time (us): 2.0078125 Std Dev: 0.4105
Benchmark for d2fixed
d2fixed Time (us): 0.8589844 Std Dev: 0.9782
internal IO Time (us): 4.4464844 Std Dev: 4.2765
I came up with the idea of implementing an effective function that converts floating point numbers to decimal strings without using internal IO when discussing the
dispfunction. And recently I have tried to work it out.The original Ryu can generate the shortest precision-preserving string of a floating point number and Ryu printf provides formatting of floating point numbers.
Based on the C and Scala version of Ryu codes, I have implemented the Fortran version of Ryu.
I think we can replace the current implementation in stdlib with Ryu-based codes. So I would like to briefly describe the API of ryu_fortran.
Currently,
ryu_fortranprovides four routines:f2shortest,d2shortest,d2fixedandd2exp.Interface
interface function f2shortest(f) result(str) real(kind=real32), intent(in) :: f character(len=:), allocatable :: str end function function d2shortest(d) result(str) real(kind=real64), intent(in) :: d character(len=:), allocatable :: str end function function d2fixed(d, precision_) result(str) real(kind=real64), intent(in) :: d integer(kind=int32), intent(in) :: precision_ character(len=:), allocatable :: str end function function d2exp(d, precision_) result(str) real(kind=real64), intent(in) :: d integer(kind=int32), intent(in) :: precision_ character(len=:), allocatable :: str end function end interfacef2shortestandd2shortestproduce shortest precision-preserving decimal strings of floating point numbers, that is, if we convert strings back to floating point values, we should get same binary representation comparing to original numbers. These two routines are suitable for cases where format is not specified. Note:f2shortestandd2shortestalways print at least two digits. For example, C version of Ryu produces "1" for1._real32whilef2shortestproduces "1.0".d2fixedandd2expdo formatting forreal64floating point numbers. The main difference between them and Fortran edit descriptors is that they don't produce "*****".With these routines, I wrote a simple prototype of
to_stringfor floating point numbers in app/main.f90. For stdlib, I think whenformatargument is not presented,f2shortestandd2shortestcan be called. But whenformatis specified, there might be a disagreement over whether we follow Fortran convention or not. The good points of Ryu formatting are fast and that it never produces "*****". But it can not control the width of formatted values, which is sometimes required.I hope in this issue we can discuss the above points and reach certain agreements.
P.S. Benchmark results (edited on 2022.2.9)