Skip to content

Commit c80f573

Browse files
committed
Merge pull request #60 from zbeekman/better-real-printing-issue-39
Better real printing issue 39
2 parents 92d6b9c + 944d9e7 commit c80f573

File tree

2 files changed

+108
-35
lines changed

2 files changed

+108
-35
lines changed

files/test2.json

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"inputs": {
3-
"t0": 0.1000000000000000E+000,
4-
"tf": 0.1100000000000000E+001,
5-
"x0": 0.9999000000000000E+004,
3+
"t0": 0.1E+0,
4+
"tf": 0.11E+1,
5+
"x0": 0.9999E+4,
66
"integer_scalar": 1,
77
"integer_array": [
88
2,
@@ -28,9 +28,9 @@
2828
"FRAME": "J2000",
2929
"CENTER": "EARTH",
3030
"DATA": [
31-
0.1000000000000000E+001,
32-
0.2000000000000000E+001,
33-
0.3000000000000000E+001
31+
0.1E+1,
32+
0.2E+1,
33+
0.3E+1
3434
]
3535
},
3636
{
@@ -39,9 +39,9 @@
3939
"FRAME": "J2000",
4040
"CENTER": "EARTH",
4141
"DATA": [
42-
0.1000000000000000E+002,
43-
0.2000000000000000E+002,
44-
0.3000000000000000E+002
42+
0.1E+2,
43+
0.2E+2,
44+
0.3E+2
4545
]
4646
},
4747
{
@@ -50,9 +50,9 @@
5050
"FRAME": "J2000",
5151
"CENTER": "EARTH",
5252
"DATA": [
53-
0.1000000000000000E+003,
54-
0.2000000000000000E+003,
55-
0.3000000000000000E+003
53+
0.1E+3,
54+
0.2E+3,
55+
0.3E+3
5656
]
5757
},
5858
{
@@ -61,9 +61,9 @@
6161
"FRAME": "J2000",
6262
"CENTER": "EARTH",
6363
"DATA": [
64-
0.1000000000000000E-002,
65-
0.2000000000000000E-002,
66-
0.3000000000000000E-002
64+
0.1E-2,
65+
0.2E-2,
66+
0.3E-2
6767
]
6868
},
6969
{
@@ -72,9 +72,9 @@
7272
"FRAME": "J2000",
7373
"CENTER": "EARTH",
7474
"DATA": [
75-
0.2000000000000000E-002,
76-
0.2000000000000000E-001,
77-
0.3000000000000000E-002
75+
0.2E-2,
76+
0.2E-1,
77+
0.3E-2
7878
]
7979
},
8080
{
@@ -83,9 +83,9 @@
8383
"FRAME": "J2000",
8484
"CENTER": "EARTH",
8585
"DATA": [
86-
0.3000000000000000E-002,
87-
0.3000000000000000E-001,
88-
0.4000000000000000E-001
86+
0.3E-2,
87+
0.3E-1,
88+
0.4E-1
8989
]
9090
}
9191
]

src/json_module.f90

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,10 @@ module json_module
116116
!default integer kind [4 bytes]
117117
integer,parameter :: IK = int32
118118

119-
!default character kind [1 byte]
119+
!default character kind [1 byte]
120120
integer,parameter :: CK = character_kinds(1)
121121

122-
!default logical kind [4 bytes]
122+
!default logical kind [4 bytes]
123123
!The statement here is to ensure a valid kind
124124
! if the compiler doesn't have a logical_kinds(3)
125125
integer,parameter :: LK = logical_kinds(min(3,size(logical_kinds)))
@@ -149,9 +149,19 @@ module json_module
149149

150150
integer(IK),parameter :: spaces_per_tab = 2 !for indenting (Note: jsonlint.com uses 4 spaces)
151151

152-
integer(IK),parameter :: max_numeric_str_len = 32
153-
character(kind=CK,len=*),parameter :: real_fmt = '(E30.16E3)' !format for real numbers
154-
character(kind=CK,len=*),parameter :: int_fmt = '(I10)' !format for integers
152+
! find out the precision of the floating point number system, in io use 4Xprecision
153+
integer(IK),parameter :: rp_safety_factor = 1
154+
integer(IK),parameter :: rp_addl_safety = 1
155+
integer(IK),parameter :: real_precision = rp_safety_factor*precision(1.0_RK) + rp_addl_safety
156+
! Get the number of possible digits in the exponent when using decimal number system
157+
integer(IK),parameter :: real_exponent_digits = ceiling( log10( &
158+
real(max(maxexponent(1.0_RK),abs(minexponent(1.0_RK))),kind=RK) &
159+
) )
160+
! 4*precision to prevent rounding errors
161+
! 6 = sign + leading 0 + decimal + 'E' + exponent sign + 1 extra
162+
integer(IK),parameter :: max_numeric_str_len = real_precision + real_exponent_digits + 6
163+
! real format set by library initialization
164+
character(kind=CK,len=*),parameter :: int_fmt = '(I0)' !minimum width format for integers
155165
character(kind=CK,len=*),parameter :: star = '*' !for invalid numbers
156166

157167
!*********************************************************
@@ -532,6 +542,7 @@ end subroutine array_callback_func
532542
! Note: the following global variables make this module non thread safe.
533543
!
534544

545+
character(kind=CK,len=:),allocatable :: real_fmt
535546
!exception handling [private variables]
536547
logical(LK) :: is_verbose = .false. !if true, all exceptions are immediately printed to console
537548
logical(LK) :: exception_thrown = .false. !the error flag
@@ -1234,20 +1245,29 @@ end subroutine json_file_get_string_vec
12341245
! AUTHOR
12351246
! Jacob Williams : 12/4/2013
12361247
!
1248+
! MODIFIED
1249+
! Izaak Beekman : 02/24/2015
1250+
!
12371251
! SOURCE
12381252

12391253
subroutine json_initialize(verbose)
12401254

12411255
implicit none
12421256

12431257
logical(LK),intent(in),optional :: verbose !mainly useful for debugging (default is false)
1244-
1258+
character(kind=CK,len=10) :: w,d,e
12451259
!optional input (if not present, value remains unchanged):
12461260
if (present(verbose)) is_verbose = verbose
12471261

12481262
!clear any errors from previous runs:
12491263
call json_clear_exceptions()
12501264

1265+
! set the output/input format for reals:
1266+
write(w,'(I0)') max_numeric_str_len
1267+
write(d,'(I0)') real_precision
1268+
write(e,'(I0)') real_exponent_digits
1269+
real_fmt = '(e' // trim(w) // '.' // trim(d) // 'e' // trim(e) // ')'
1270+
12511271
!Just in case, clear these global variables also:
12521272
pushed_index = 0
12531273
pushed_char = ''
@@ -1553,7 +1573,7 @@ subroutine json_value_remove(me,destroy)
15531573

15541574
if (associated(me%parent)) then
15551575

1556-
parent => me%parent
1576+
parent => me%parent
15571577

15581578
if (associated(me%next)) then
15591579

@@ -1562,7 +1582,7 @@ subroutine json_value_remove(me,destroy)
15621582
next => me%next
15631583
nullify(me%next)
15641584

1565-
if (associated(me%previous)) then
1585+
if (associated(me%previous)) then
15661586
!there are earlier items in the list
15671587
previous => me%previous
15681588
previous%next => next
@@ -2811,7 +2831,7 @@ recursive subroutine json_value_print(this,iunit,str,indent,need_comma,colon,is_
28112831

28122832
end do
28132833

2814-
!indent the closing array character:
2834+
!indent the closing array character:
28152835
call write_it( repeat(space, max(0,spaces-spaces_per_tab))//end_array,&
28162836
comma=print_comma )
28172837
nullify(element)
@@ -3696,10 +3716,10 @@ subroutine json_get_string(this, path, value, found)
36963716

36973717
s = pre//c//post
36983718

3699-
n = n-1 !backslash character has been
3719+
n = n-1 !backslash character has been
37003720
! removed from the string
37013721

3702-
case('u') !expecting 4 hexadecimal digits after
3722+
case('u') !expecting 4 hexadecimal digits after
37033723
! the escape character [\uXXXX]
37043724

37053725
!for now, we are just printing them as is
@@ -3987,7 +4007,7 @@ subroutine json_parse(file, p, unit, str)
39874007
return
39884008
end if
39894009

3990-
iunit = unit
4010+
iunit = unit
39914011

39924012
!check to see if the file is already open
39934013
! if it is, then use it, otherwise open the file with the name given.
@@ -4614,6 +4634,9 @@ end subroutine to_double
46144634
! AUTHOR
46154635
! Jacob Williams
46164636
!
4637+
! MODIFIED
4638+
! Izaak Beekman : 02/24/2015
4639+
!
46174640
! SOURCE
46184641

46194642
subroutine to_string(me,val,name)
@@ -5233,7 +5256,7 @@ recursive function pop_char(unit, str, eof, skip_ws) result(popped)
52335256

52345257
end if
52355258

5236-
if (iachar(c) <= 31) then !JW : fixed so it will read spaces
5259+
if (iachar(c) <= 31) then !JW : fixed so it will read spaces
52375260
! in the string (was 32)
52385261

52395262
! non printing ascii characters
@@ -5348,12 +5371,62 @@ subroutine real_to_string(rval,str)
53485371
real(RK),intent(in) :: rval
53495372
character(kind=CK,len=*),intent(out) :: str
53505373

5351-
integer(IK) :: istat
5374+
character(kind=CK,len=len(str)) :: significand, expnt
5375+
character(kind=CK,len=2) :: separator
5376+
integer(IK) :: istat, exp_start, decimal_pos, sig_trim, exp_trim, i
53525377

53535378
write(str,fmt=real_fmt,iostat=istat) rval
53545379

53555380
if (istat==0) then
53565381
str = adjustl(str)
5382+
exp_start = scan(str,CK_'eEdD')
5383+
if (exp_start == 0) exp_start = scan(str,CK_'-+',back=.true.)
5384+
decimal_pos = scan(str,CK_'.')
5385+
if (exp_start /= 0) separator = str(exp_start:exp_start)
5386+
if (exp_start > 0 .and. exp_start < decimal_pos) then !signed, exponent-less float
5387+
significand = str
5388+
sig_trim = len(trim(significand))
5389+
do i = len(trim(significand)),decimal_pos+2,-1 !look from right to left at 0s
5390+
!but save one after the decimal place
5391+
if (significand(i:i) == CK_'0') then
5392+
sig_trim = i-1
5393+
else
5394+
exit
5395+
end if
5396+
end do
5397+
str = trim(significand(1:sig_trim))
5398+
else if (exp_start > decimal_pos) then !float has exponent
5399+
significand = str(1:exp_start-1)
5400+
sig_trim = len(trim(significand))
5401+
do i = len(trim(significand)),decimal_pos+2,-1 !look from right to left at 0s
5402+
if (significand(i:i) == CK_'0') then
5403+
sig_trim = i-1
5404+
else
5405+
exit
5406+
end if
5407+
end do
5408+
expnt = adjustl(str(exp_start+1:))
5409+
if (expnt(1:1) == CK_'+' .or. expnt(1:1) == CK_'-') then
5410+
separator = trim(adjustl(separator))//expnt(1:1)
5411+
exp_start = exp_start + 1
5412+
expnt = adjustl(str(exp_start+1:))
5413+
end if
5414+
exp_trim = 1
5415+
do i = 1,(len(trim(expnt))-1) !look at exponent leading zeros saving last
5416+
if (expnt(i:i) == CK_'0') then
5417+
exp_trim = i+1
5418+
else
5419+
exit
5420+
end if
5421+
end do
5422+
str = trim(adjustl(significand(1:sig_trim)))// &
5423+
trim(adjustl(separator))// &
5424+
trim(adjustl(expnt(exp_trim:)))
5425+
5426+
!else ! mal-formed real, BUT this code should be unreachable
5427+
5428+
end if
5429+
53575430
else
53585431
str = repeat(star,len(str))
53595432
end if

0 commit comments

Comments
 (0)