Skip to content

Commit dae9d4b

Browse files
authored
Merge pull request #1129 from MadhurKumar004/fix-1055
Fix: logspace generate wrong result for integer arguments
2 parents fb63d7e + 61d7c44 commit dae9d4b

4 files changed

Lines changed: 54 additions & 10 deletions

File tree

doc/specs/stdlib_math.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ For function calls where the `base` is specified, the `type` and `kind` of the r
234234
| " " | " " | `Integer` | `complex(KIND)` |
235235
| `Integer` | " " | `real(KIND)` | `real(KIND)` |
236236
| " " | " " | `complex(KIND)` | `complex(KIND)` |
237-
| " " | " " | `Integer` | `Integer` |
237+
| " " | " " | `Integer` | `real(dp)` |
238238

239239
#### Examples
240240

src/math/stdlib_math.fypp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ module stdlib_math
301301
integer, intent(in) :: end
302302
integer, intent(in) :: n
303303
integer, intent(in) :: base
304-
! integer endpoints + integer base = integer result
305-
integer :: res(max(n, 0))
304+
! integer endpoints + integer base = real(dp) result
305+
real(dp) :: res(max(n, 0))
306306
end function ${RName}$
307307

308308

src/math/stdlib_math_logspace.fypp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,30 @@ contains
6969
#:for k1 in REAL_KINDS
7070
#:set RName = rname("logspace", 1, "integer(int32)", "int32", "n_r" + str(k1) + "base")
7171
module procedure ${RName}$
72-
integer :: exponents(max(n, 0))
73-
exponents = linspace(start, end, n)
72+
real(${k1}$) :: exponents(max(n, 0))
73+
exponents = linspace(real(start, kind=${k1}$), real(end, kind=${k1}$), n)
7474
res = base ** exponents
75+
if (n > 1) res(1) = base ** start
76+
if (n > 0) res(n) = base ** end
7577
end procedure
7678

7779
#:set RName = rname("logspace", 1, "integer(int32)", "int32", "n_c" + str(k1) + "base")
7880
module procedure ${RName}$
79-
integer :: exponents(max(n, 0))
80-
exponents = linspace(start, end, n)
81+
complex(${k1}$) :: exponents(max(n, 0))
82+
exponents = cmplx(linspace(real(start, kind=${k1}$), real(end, kind=${k1}$), n), 0.0_${k1}$)
8183
res = base ** exponents
84+
if (n > 1) res(1) = base ** start
85+
if (n > 0) res(n) = base ** end
8286
end procedure
8387
#:endfor
8488

8589
#:set RName = rname("logspace", 1, "integer(int32)", "int32", "n_ibase")
8690
module procedure ${RName}$
87-
integer :: exponents(max(n, 0))
88-
exponents = linspace(start, end, n)
91+
real(dp) :: exponents(max(n, 0))
92+
exponents = linspace(real(start, kind=dp), real(end, kind=dp), n)
8993
res = base ** exponents
94+
if (n > 1) res(1) = base ** real(start, kind=dp)
95+
if (n > 0) res(n) = base ** real(end, kind=dp)
9096
end procedure
9197

9298

test/math/test_logspace.f90

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ subroutine collect_logspace(testsuite)
3131
new_unittest("logspace_default", test_logspace_default), &
3232
new_unittest("logspace_base_2", test_logspace_base_2), &
3333
new_unittest("logspace_base_2_cmplx_start", test_logspace_base_2_cmplx_start), &
34-
new_unittest("logspace_base_i_int_start", test_logspace_base_i_int_start) &
34+
new_unittest("logspace_base_i_int_start", test_logspace_base_i_int_start), &
35+
new_unittest("logspace_int_overflow", test_logspace_int_overflow) &
3536
]
3637

3738
end subroutine collect_logspace
@@ -242,6 +243,43 @@ subroutine test_logspace_base_i_int_start(error)
242243

243244
end subroutine
244245

246+
! Regression test for issue #1055: integer start/end caused overflow in
247+
! intermediate integer arithmetic, producing garbage results.
248+
subroutine test_logspace_int_overflow(error)
249+
!> Error handling
250+
type(error_type), allocatable, intent(out) :: error
251+
252+
integer, parameter :: n = 3
253+
integer, parameter :: start = 10
254+
integer, parameter :: end = 23
255+
real(dp) :: expected_proportion
256+
integer :: i
257+
258+
real(dp), allocatable :: x(:)
259+
260+
x = logspace(start, end, n)
261+
262+
expected_proportion = 10.0_dp ** ( real(end - start, dp) / real(n - 1, dp) )
263+
264+
call check(error, size(x), n, "Array not allocated to appropriate size")
265+
if (allocated(error)) return
266+
call check(error, x(1), 10.0_dp ** start, &
267+
& "Initial value not equal to 10^start (possible integer overflow)", &
268+
& thr=abs(10.0_dp ** start) * TOLERANCE_DP)
269+
if (allocated(error)) return
270+
call check(error, x(n), 10.0_dp ** end, &
271+
& "Final value not equal to 10^end (possible integer overflow)", &
272+
& thr=abs(10.0_dp ** end) * TOLERANCE_DP)
273+
if (allocated(error)) return
274+
275+
do i = 1, n-1
276+
call check(error, x(i + 1) / x(i), expected_proportion, &
277+
& thr=abs(expected_proportion) * TOLERANCE_DP)
278+
if (allocated(error)) return
279+
end do
280+
281+
end subroutine
282+
245283

246284
end module
247285

0 commit comments

Comments
 (0)