How to write this in Fortran? - matlab

I have the following MATLAB code which does the following.
Suppose I have 3 investments of 10 units. Matrix exits has a value of 1 if the investment is exited. Matrix pos tells me the return of each of the three investments. Then the last line of the code computes the total money earned on exited investments.
I am trying to write a similar lines of code in Fortran. Also below my Fortran attempt.
clear all
X = 10;
ret(1,1) = -0.05;
ret(2,1) = 0.15;
exits = [1 0 1];
pos = [1 1 2];
ret1 = (pos == 1) .* ret(1,1) + (pos == 2) .* ret(2,1);
inv = sum(X * ones(1,3) .* (exits) .* exp(ret1));
My Fortran code:
PROGRAM Matlab_replication
IMPLICIT NONE
INTEGER, DIMENSION(1,1) :: X = 10
REAL, DIMENSION(2,1) :: ret
INTEGER, DIMENSION(1,3) :: exits
INTEGER, DIMENSION(1,3) :: pos
REAL, DIMENSION(1,3) :: ret1
REAL, DIMENSION(1,3) :: ret2
REAL, DIMENSION(1,3) :: ones = 1.0
REAL, DIMENSION(1,3) :: X1
REAL :: inv
ret(1,1) = -0.05
ret(2,1) = 0.15
exits(1,1) = 1
exits(1,2) = 0
exits(1,3) = 1
pos(1,1) = 1
pos(1,2) = 1
pos(1,3) = 2
X1(1,:) = X(1,1) * ones(1,:)
ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)
ret2(1,:) = exp(ret1(1,:))
inv = sum(X1(1,:) * exits(1,:)* ret2(1,:))
end program
Somehow the line ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1) is not delivering what I am looking for. Also I had to create two additional variables versus the MATLAB code X1 and ret2. Any way to avoid this?

This may be an extended comment rather than an answer ...
The expression
(pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)
mixes types in a way unacceptable to Fortran. The first term, (pos == 1) is of type logical and evaluates to either .true. or .false.. That is not something that can then be multiplied by a number, or by anything else for that matter.
Actually, matters are slightly worse than I first realised, since pos is an array. Do you expect an array of results, or for a single result from that term ?
I'm not sure what you are trying to do, but you'll need to transform (pos == 1) to a number somehow if you want to multiply it. It is fairly easy to write a Fortran function to return 1 (or whatever you want) for a .true. input, and another number for a .false. input.
Finally I'm surprised that your Fortran code is returning anything at all as you assert in your comment. I'm surprised that it compiles.

pos == 1 in Matlab returns an array consisting of 1 and 0, while it returns an array consisting of .true. and .false. in Fortran (as suggested by #HighPerformanceMark). So, you need to take care of this difference somehow. There are various ways for this, and one such example is like this:
real :: ret( 2 ), vtmp( 3 ), inv, x
integer :: exits( 3 ), pos( 3 )
x = 10.0
ret = [ -0.05, 0.15 ]
exits = [ 1, 0, 1 ]
pos = [ 1, 1, 2 ]
vtmp = abs([ integer:: pos == 1 ]) * ret( 1 ) + abs([ integer:: pos == 2 ]) * ret( 2 )
inv = sum( x * exits * exp( vtmp ) )
where I have assumed gfortran or Intel fortran and changed all 2-D arrays in the original code to 1-D arrays for simplicity.
For other compilers, the above code may be syntactically not allowed; in that case it may be useful to define some utility functions like
module filter_mod
implicit none
interface filter
module procedure filter1D, filter2D
end interface
contains
function filter1D( mask ) result( ints )
logical :: mask(:)
integer :: ints( size( mask ) )
ints = 0 ; where( mask ) ints = 1
end function
function filter2D( mask ) result( ints )
logical :: mask(:,:)
integer :: ints( size( mask, 1 ), size( mask, 2 ) )
ints = 0 ; where( mask ) ints = 1
end function
end module
and modify the original code as
PROGRAM Matlab_replication
use filter_mod
IMPLICIT NONE
...
ret1 = filter( pos == 1 ) * ret(1,1) + filter( pos == 2 ) * ret(2,1)
inv = sum( X(1,1) * exits * exp( ret1 ) )
which hopefully makes the translation from Matlab straight-forward.
EDIT: Actually, use of merge() function seems to be the simplest solution (thanks to #francescalus). With this function the first and second codes can be rewritten as
vtmp = merge( ret(1), 0.0, pos == 1 ) + merge( ret(2), 0.0, pos == 2 )
and
ret1 = merge( ret(1,1), 0.0, pos == 1 ) + merge( ret(2,1), 0.0, pos == 2 )
Because merge() returns an array with the same shape as pos, it is very straight-forward to use even for multi-dimensional arrays.

Related

Speed in Matlab vs. Julia vs. Fortran

I am playing around with different languages to solve a simple value function iteration problem where I loop over a state-space grid. I am trying to understand the performance differences and how I could tweak each code. For posterity I have posted full length working examples for each language below. However, I believe that most of the tweaking is to be done in the while loop. I am a bit confused what I am doing wrong in Fortran as the speed seems subpar.
Matlab ~2.7secs : I am avoiding a more efficient solution using the repmat function for now to keep the codes comparable. Code seems to be automatically multithreaded onto 4 threads
beta = 0.98;
sigma = 0.5;
R = 1/beta;
a_grid = linspace(0,100,1001);
tic
[V_mat, next_mat] = valfun(beta, sigma, R ,a_grid);
toc
where valfun()
function [V_mat, next_mat] = valfun(beta, sigma, R, a_grid)
zeta = 1-1/sigma;
len = length(a_grid);
V_mat = zeros(2,len);
next_mat = zeros(2,len);
u = zeros(2,len,len);
c = zeros(2,len,len);
for i = 1:len
c(1,:,i) = a_grid(i) - a_grid/R + 20.0;
c(2,:,i) = a_grid(i) - a_grid/R;
end
u = c.^zeta * zeta^(-1);
u(c<=0) = -1e8;
tol = 1e-4;
outeriter = 0;
diff = 1000.0;
while (diff>tol) %&& (outeriter<20000)
outeriter = outeriter + 1;
V_last = V_mat;
for i = 1:len
[V_mat(1,i), next_mat(1,i)] = max( u(1,:,i) + beta*V_last(2,:));
[V_mat(2,i), next_mat(2,i)] = max( u(2,:,i) + beta*V_last(1,:));
end
diff = max(abs(V_mat - V_last));
end
fprintf("\n Value Function converged in %i steps. \n", outeriter)
end
Julia (after compilation) ~5.4secs (4 threads (9425469 allocations: 22.43 GiB)), ~7.8secs (1 thread (2912564 allocations: 22.29 GiB))
[EDIT: after adding correct broadcasting and #views its only 1.8-2.1seconds now, see below!]
using LinearAlgebra, UnPack, BenchmarkTools
struct paramsnew
β::Float64
σ::Float64
R::Float64
end
function valfun(params, a_grid)
#unpack β,σ, R = params
ζ = 1-1/σ
len = length(a_grid)
V_mat = zeros(2,len)
next_mat = zeros(2,len)
u = zeros(2,len,len)
c = zeros(2,len,len)
#inbounds for i in 1:len
c[1,:,i] = #. a_grid[i] - a_grid/R .+ 20.0
c[2,:,i] = #. a_grid[i] - a_grid/R
end
u = c.^ζ * ζ^(-1)
u[c.<=0] .= typemin(Float64)
tol = 1e-4
outeriter = 0
test = 1000.0
while test>tol
outeriter += 1
V_last = deepcopy(V_mat)
#inbounds Threads.#threads for i in 1:len # loop over grid points
V_mat[1,i], next_mat[1,i] = findmax( u[1,:,i] .+ β*V_last[2,:])
V_mat[2,i], next_mat[2,i] = findmax( u[2,:,i] .+ β*V_last[1,:])
end
test = maximum( abs.(V_mat - V_last)[.!isnan.( V_mat - V_last )])
end
print("\n Value Function converged in ", outeriter, " steps.")
return V_mat, next_mat
end
a_grid = collect(0:0.1:100)
p1 = paramsnew(0.98, 1/2, 1/0.98);
#time valfun(p1,a_grid)
print("\n should be compiled now \n")
#btime valfun(p1,a_grid)
Fortran (O3, mkl, qopenmp) ~9.2secs: I also must be doing something wrong when declaring the openmp variables as the compilation will crash for some grid sizes when using openmp (SIGSEGV error).
module mod_calc
use omp_lib
implicit none
integer, parameter :: dp = selected_real_kind(33,4931), len = 1001
public :: dp, len
contains
subroutine linspace(from, to, array)
real(dp), intent(in) :: from, to
real(dp), intent(out) :: array(:)
real(dp) :: range
integer :: n, i
n = size(array)
range = to - from
if (n == 0) return
if (n == 1) then
array(1) = from
return
end if
do i=1, n
array(i) = from + range * (i - 1) / (n - 1)
end do
end subroutine
subroutine calc_val()
real(dp):: bbeta, sigma, R, zeta, tol, test
real(dp):: a_grid(len), V_mat(2,len), V_last(2,len), &
u(len,len,2), c(len,len,2)
integer :: outeriter, i, sss, next_mat(2,len), fu
character(len=*), parameter :: FILE_NAME = 'data.txt' ! File name.
call linspace(from=0._dp, to=100._dp, array=a_grid)
bbeta = 0.98
sigma = 0.5
R = 1.0/0.98
zeta = 1.0 - 1.0/sigma
tol = 1e-4
test = 1000.0
outeriter = 0
do i = 1,len
c(:,i,1) = a_grid(i) - a_grid/R + 20.0
c(:,i,2) = a_grid(i) - a_grid/R
end do
u = c**zeta * 1.0/zeta
where (c<=0)
u = -1e6
end where
V_mat = 0.0
next_mat = 0.0
do while (test>tol .and. outeriter<20000)
outeriter = outeriter+1
V_last = V_mat
!$OMP PARALLEL DEFAULT(NONE) &
!$OMP SHARED(V_mat, next_mat,V_last, u, bbeta) &
!$OMP PRIVATE(i)
!$OMP DO SCHEDULE(static)
do i=1,len
V_mat(1,i) = maxval(u(:,i,1) + bbeta*V_last(2,:))
next_mat(1,i) = maxloc(u(:,i,1) + bbeta*V_last(2,:),1)
V_mat(2,i) = maxval(u(:,i,2) + bbeta*V_last(1,:))
next_mat(2,i) = maxloc(u(:,i,2) + bbeta*V_last(1,:),1)
end do
!$OMP END DO
!$OMP END PARALLEL
test = maxval(abs(log(V_last/V_mat)))
end do
end subroutine
end module mod_calc
program main
use mod_calc
implicit none
integer:: clck_counts_beg,clck_rate,clck_counts_end
call omp_set_num_threads(4)
call system_clock ( clck_counts_beg, clck_rate )
call calc_val()
call system_clock ( clck_counts_end, clck_rate )
write (*, '("Time = ",f6.3," seconds.")') (clck_counts_end - clck_counts_beg) / real(clck_rate)
end program main
There should be ways to reduce the amount of allocations (Julia reports 32-45% gc time!) but for now I am too novice to see them, so any comments and tipps are welcome.
Edit:
Adding #views and correct broadcasting to the while loop improved the Julia speed considerably (as expected, I guess) and hence beats the Matlab loop now. With 4 threads the code now takes only 1.97secs. Specifically,
#inbounds for i in 1:len
c[1,:,i] = #views #. a_grid[i] - a_grid/R .+ 20.0
c[2,:,i] = #views #. a_grid[i] - a_grid/R
end
u = #. c^ζ * ζ^(-1)
#. u[c<=0] = typemin(Float64)
while test>tol && outeriter<20000
outeriter += 1
V_last = deepcopy(V_mat)
#inbounds Threads.#threads for i in 1:len # loop over grid points
V_mat[1,i], next_mat[1,i] = #views findmax( #. u[1,:,i] + β*V_last[2,:])
V_mat[2,i], next_mat[2,i] = #views findmax( #. u[2,:,i] + β*V_last[1,:])
end
test = #views maximum( #. abs(V_mat - V_last)[!isnan( V_mat - V_last )])
end
The reason the fortran is so slow is that it is using quadruple precision - I don't know Julia or Matlab but it looks as though double precision is being used in that case. Further as noted in the comments some of the loop orders are incorrect for Fortran, and also you are not consistent in your use of precision in the Fortran code, most of your constants are single precision. Correcting all these leads to the following:
Original: test = 9.83440674663232047922921588613472439E-0005 Time =
31.413 seconds.
Optimised: test = 9.8343643237979391E-005 Time = 0.912 seconds.
Note I have turned off parallelisation for these, all results are single threaded. Code is below:
module mod_calc
!!$ use omp_lib
implicit none
!!$ integer, parameter :: dp = selected_real_kind(33,4931), len = 1001
integer, parameter :: dp = selected_real_kind(15), len = 1001
public :: dp, len
contains
subroutine linspace(from, to, array)
real(dp), intent(in) :: from, to
real(dp), intent(out) :: array(:)
real(dp) :: range
integer :: n, i
n = size(array)
range = to - from
if (n == 0) return
if (n == 1) then
array(1) = from
return
end if
do i=1, n
array(i) = from + range * (i - 1) / (n - 1)
end do
end subroutine
subroutine calc_val()
real(dp):: bbeta, sigma, R, zeta, tol, test
real(dp):: a_grid(len), V_mat(len,2), V_last(len,2), &
u(len,len,2), c(len,len,2)
integer :: outeriter, i, sss, next_mat(2,len), fu
character(len=*), parameter :: FILE_NAME = 'data.txt' ! File name.
call linspace(from=0._dp, to=100._dp, array=a_grid)
bbeta = 0.98_dp
sigma = 0.5_dp
R = 1.0_dp/0.98_dp
zeta = 1.0_dp - 1.0_dp/sigma
tol = 1e-4_dp
test = 1000.0_dp
outeriter = 0
do i = 1,len
c(:,i,1) = a_grid(i) - a_grid/R + 20.0_dp
c(:,i,2) = a_grid(i) - a_grid/R
end do
u = c**zeta * 1.0_dp/zeta
where (c<=0)
u = -1e6_dp
end where
V_mat = 0.0_dp
next_mat = 0.0_dp
do while (test>tol .and. outeriter<20000)
outeriter = outeriter+1
V_last = V_mat
!$OMP PARALLEL DEFAULT(NONE) &
!$OMP SHARED(V_mat, next_mat,V_last, u, bbeta) &
!$OMP PRIVATE(i)
!$OMP DO SCHEDULE(static)
do i=1,len
V_mat(i,1) = maxval(u(:,i,1) + bbeta*V_last(:, 2))
next_mat(i,1) = maxloc(u(:,i,1) + bbeta*V_last(:, 2),1)
V_mat(i,2) = maxval(u(:,i,2) + bbeta*V_last(:, 1))
next_mat(i,2) = maxloc(u(:,i,2) + bbeta*V_last(:, 1),1)
end do
!$OMP END DO
!$OMP END PARALLEL
test = maxval(abs(log(V_last/V_mat)))
end do
Write( *, * ) test
end subroutine
end module mod_calc
program main
use mod_calc
implicit none
integer:: clck_counts_beg,clck_rate,clck_counts_end
!!$ call omp_set_num_threads(2)
call system_clock ( clck_counts_beg, clck_rate )
call calc_val()
call system_clock ( clck_counts_end, clck_rate )
write (*, '("Time = ",f6.3," seconds.")') (clck_counts_end - clck_counts_beg) / real(clck_rate)
end program main
Compilation / linking:
ian#eris:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ian#eris:~/work/stack$ gfortran -Wall -Wextra -O3 jul.f90
jul.f90:36:48:
character(len=*), parameter :: FILE_NAME = 'data.txt' ! File name.
1
Warning: Unused parameter ‘file_name’ declared at (1) [-Wunused-parameter]
jul.f90:35:57:
integer :: outeriter, i, sss, next_mat(2,len), fu
1
Warning: Unused variable ‘fu’ declared at (1) [-Wunused-variable]
jul.f90:35:36:
integer :: outeriter, i, sss, next_mat(2,len), fu
1
Warning: Unused variable ‘sss’ declared at (1) [-Wunused-variable]
Running:
ian#eris:~/work/stack$ ./a.out
9.8343643237979391E-005
Time = 0.908 seconds.
What #Ian Bush says in his answer about the dual precision is correct. Moreover,
You will likely not need openmp for the kind of parallelization you have done in your code. The Fortran's intrinsic do concurrent() will automatically parallelize the loop for you (when the code is compiled with the parallel flag of the respective compiler).
Also, the where elsewhere construct is slow as it often requires the creation of a logical mask array and then applying it in a do-loop. You can use do concurrent() in place of where to both avoid the extra temporary array creation and parallelize the computation on multiple cores.
Also, when comparing 64bit precision numbers, it's good to make sure both values are the same type and kind to avoid an implicit type/kind conversion before the comparison is made.
Also, the calculation of a_grid(i) - a_grid/R in computing the c array is redundant and can be avoided in the subsequent line.
Here is the modified optimized parallel Fortran code without any OpenMP,
module mod_calc
use iso_fortran_env, only: dp => real64
implicit none
integer, parameter :: len = 1001
public :: dp, len
contains
subroutine linspace(from, to, array)
real(dp), intent(in) :: from, to
real(dp), intent(out) :: array(:)
real(dp) :: range
integer :: n, i
n = size(array)
range = to - from
if (n == 0) return
if (n == 1) then
array(1) = from
return
end if
do concurrent(i=1:n)
array(i) = from + range * (i - 1) / (n - 1)
end do
end subroutine
subroutine calc_val()
implicit none
real(dp) :: bbeta, sigma, R, zeta, tol, test
real(dp) :: a_grid(len), V_mat(len,2), V_last(len,2), u(len,len,2), c(len,len,2)
integer :: outeriter, i, j, k, sss, next_mat(2,len), fu
character(len=*), parameter :: FILE_NAME = 'data.txt' ! File name.
call linspace(from=0._dp, to=100._dp, array=a_grid)
bbeta = 0.98_dp
sigma = 0.5_dp
R = 1.0_dp/0.98_dp
zeta = 1.0_dp - 1.0_dp/sigma
tol = 1e-4_dp
test = 1000.0_dp
outeriter = 0
do concurrent(i=1:len)
c(1:len,i,2) = a_grid(i) - a_grid/R
c(1:len,i,1) = c(1:len,i,2) + 20.0_dp
end do
u = c**zeta * 1.0_dp/zeta
do concurrent(i=1:len, j=1:len, k=1:2)
if (c(i,j,k)<=0._dp) u(i,j,k) = -1e6_dp
end do
V_mat = 0.0_dp
next_mat = 0.0_dp
do while (test>tol .and. outeriter<20000)
outeriter = outeriter + 1
V_last = V_mat
do concurrent(i=1:len)
V_mat(i,1) = maxval(u(:,i,1) + bbeta*V_last(:, 2))
next_mat(i,1) = maxloc(u(:,i,1) + bbeta*V_last(:, 2),1)
V_mat(i,2) = maxval(u(:,i,2) + bbeta*V_last(:, 1))
next_mat(i,2) = maxloc(u(:,i,2) + bbeta*V_last(:, 1),1)
end do
test = maxval(abs(log(V_last/V_mat)))
end do
Write( *, * ) test
end subroutine
end module mod_calc
program main
use mod_calc
implicit none
integer:: clck_counts_beg,clck_rate,clck_counts_end
call system_clock ( clck_counts_beg, clck_rate )
call calc_val()
call system_clock ( clck_counts_end, clck_rate )
write (*, '("Time = ",f6.3," seconds.")') (clck_counts_end - clck_counts_beg) / real(clck_rate)
end program main
Compiling your original code with /standard-semantics /F0x1000000000 /O3 /Qip /Qipo /Qunroll /Qunroll-aggressive /inline:all /Ob2 /Qparallel Intel Fortran compiler flags, yields the following timing,
original.exe
Time = 37.284 seconds.
compiling and running the parallel concurrent Fortran code in the above (on at most 4 cores, if any at all is used) yields,
concurrent.exe
Time = 0.149 seconds.
For comparison, this MATLAB's timing,
Value Function converged in 362 steps.
Elapsed time is 3.575691 seconds.
One last tip: There are several vectorized array computations and loops in the above code that can still be merged together to even further improve the speed of your Fortran code. For example,
u = c**zeta * 1.0_dp/zeta
do concurrent(i=1:len, j=1:len, k=1:2)
if (c(i,j,k)<=0._dp) u(i,j,k) = -1e6_dp
end do
in the above code can be all merged with the do concurrent loop appearing before it,
do concurrent(i=1:len)
c(1:len,i,2) = a_grid(i) - a_grid/R
c(1:len,i,1) = c(1:len,i,2) + 20.0_dp
end do
If you decide to do so, then you can define an auxiliary variable inverse_zeta = 1.0_dp / zeta to use in the computation of u inside the loop instead of using * 1.0_dp / zeta, thus avoiding the extra division (which is more costly than multiplication), without degrading the readability of the code.

How do I generate random numbers in such range? [duplicate]

This question already has answers here:
Generate random number with given probability matlab
(7 answers)
Draw random numbers from pre-specified probability mass function in Matlab
(1 answer)
Closed 3 years ago.
I want to generate some random numbers, that is for such distribution:
10% of them are in Category A (T = 6),
40% of them are in Category B (T = 8),
40% of them are in Category C (T = 10),
10% of them are in Category D (T = 12).
I just started to learn MATLAB and I tried rand(x) and randn(x) but it seems neither of them can do that?
You'll have to set up some kind of mapping from the uniformly distributed random numbers you get from rand to your desired values, i.e. with respect to the wanted distribution.
In my solution, I generate random numbers using rand, and map them to integers 1, 2, 3, 4 as well as to (categorical) characters A, B, C, D. I built a whole function to support variable amount of input arguments to mimic the behaviour of rand.
That's the code of the myRand function:
function [rn, in, ch] = myRand(varargin)
% No input arguments.
if (numel(varargin) == 0)
rn = rand();
% One input argument; might be a scalar or an array.
elseif (numel(varargin) == 1)
a = varargin{1};
if (!isnumeric(a))
error('myRand: argument must be numeric');
end
rn = rand(a);
% More than one input argument; must be scalars.
elseif (numel(varargin) > 1)
if (!all(cellfun(#(x)isnumeric(x), varargin)))
error('myRand: arguments must be numeric');
end
if (!all(cellfun(#(x)isscalar(x), varargin)))
error('myRand: arguments must be scalar');
end
rn = rand(varargin{:});
end
in = zeros(size(rn));
in((0 <= rn) & (rn < 0.1)) = 1;
in((0.1 <= rn) & (rn < 0.5)) = 2;
in((0.5 <= rn) & (rn < 0.9)) = 3;
in((0.9 <= rn) & (rn < 1)) = 4;
ch = cell(size(rn));
ch((0 <= rn) & (rn < 0.1)) = { 'A' };
ch((0.1 <= rn) & (rn < 0.5)) = { 'B' };
ch((0.5 <= rn) & (rn < 0.9)) = { 'C' };
ch((0.9 <= rn) & (rn < 1)) = { 'D' };
end
And, here's some test code with the corresponding outputs:
% Single random number with integer and category
[rn, in, ch] = myRand()
% Multiple random numbers with integers and categories (array input)
[rn, in, ch] = myRand([2, 3])
% Multiple random numbers with integers and categories (multiple scalars input)
[rn, in, ch] = myRand(2, 3)
rn = 0.19904
in = 2
ch =
{
[1,1] = B
}
rn =
0.206294 0.420426 0.835194
0.793874 0.593371 0.034055
in =
2 2 3
3 3 1
ch =
{
[1,1] = B
[2,1] = C
[1,2] = B
[2,2] = C
[1,3] = C
[2,3] = A
}
rn =
0.96223 0.87840 0.49925
0.54890 0.88436 0.92096
in =
4 3 2
3 3 4
ch =
{
[1,1] = D
[2,1] = C
[1,2] = C
[2,2] = C
[1,3] = B
[2,3] = D
}
Hope that helps!
Disclaimer: I tested the code with Octave 5.1.0, but I'm quite sure, that it should be fully MATLAB-compatible. If not, please leave a comment, and I'll try to fix possible issues.

Integer division in Scala [duplicate]

(note: not the same as this other question since the OP never explicitly specified rounding towards 0 or -Infinity)
JLS 15.17.2 says that integer division rounds towards zero. If I want floor()-like behavior for positive divisors (I don't care about the behavior for negative divisors), what's the simplest way to achieve this that is numerically correct for all inputs?
int ifloor(int n, int d)
{
/* returns q such that n = d*q + r where 0 <= r < d
* for all integer n, d where d > 0
*
* d = 0 should have the same behavior as `n/d`
*
* nice-to-have behaviors for d < 0:
* option (a). same as above:
* returns q such that n = d*q + r where 0 <= r < -d
* option (b). rounds towards +infinity:
* returns q such that n = d*q + r where d < r <= 0
*/
}
long lfloor(long n, long d)
{
/* same behavior as ifloor, except for long integers */
}
(update: I want to have a solution both for int and long arithmetic.)
If you can use third-party libraries, Guava has this: IntMath.divide(int, int, RoundingMode.FLOOR) and LongMath.divide(int, int, RoundingMode.FLOOR). (Disclosure: I contribute to Guava.)
If you don't want to use a third-party library for this, you can still look at the implementation.
(I'm doing everything for longs since the answer for ints is the same, just substitute int for every long and Integer for every Long.)
You could just Math.floor a double division result, otherwise...
Original answer:
return n/d - ( ( n % d != 0 ) && ( (n<0) ^ (d<0) ) ? 1 : 0 );
Optimized answer:
public static long lfloordiv( long n, long d ) {
long q = n/d;
if( q*d == n ) return q;
return q - ((n^d) >>> (Long.SIZE-1));
}
(For completeness, using a BigDecimal with a ROUND_FLOOR rounding mode is also an option.)
New edit: Now I'm just trying to see how far it can be optimized for fun. Using Mark's answer the best I have so far is:
public static long lfloordiv2( long n, long d ){
if( d >= 0 ){
n = -n;
d = -d;
}
long tweak = (n >>> (Long.SIZE-1) ) - 1;
return (n + tweak) / d + tweak;
}
(Uses cheaper operations than the above, but slightly longer bytecode (29 vs. 26)).
There's a rather neat formula for this that works when n < 0 and d > 0: take the bitwise complement of n, do the division, and then take the bitwise complement of the result.
int ifloordiv(int n, int d)
{
if (n >= 0)
return n / d;
else
return ~(~n / d);
}
For the remainder, a similar construction works (compatible with ifloordiv in the sense that the usual invariant ifloordiv(n, d) * d + ifloormod(n, d) == n is satisfied) giving a result that's always in the range [0, d).
int ifloormod(int n, int d)
{
if (n >= 0)
return n % d;
else
return d + ~(~n % d);
}
For negative divisors, the formulas aren't quite so neat. Here are expanded versions of ifloordiv and ifloormod that follow your 'nice-to-have' behavior option (b) for negative divisors.
int ifloordiv(int n, int d)
{
if (d >= 0)
return n >= 0 ? n / d : ~(~n / d);
else
return n <= 0 ? n / d : (n - 1) / d - 1;
}
int ifloormod(int n, int d)
{
if (d >= 0)
return n >= 0 ? n % d : d + ~(~n % d);
else
return n <= 0 ? n % d : d + 1 + (n - 1) % d;
}
For d < 0, there's an unavoidable problem case when d == -1 and n is Integer.MIN_VALUE, since then the mathematical result overflows the type. In that case, the formula above returns the wrapped result, just as the usual Java division does. As far as I'm aware, this is the only corner case where we silently get 'wrong' results.
return BigDecimal.valueOf(n).divide(BigDecimal.valueOf(d), RoundingMode.FLOOR).longValue();

lapack - addressing for fully packed rectangular format

I would like to use the LAPACK routines for factorisation and inversion of matrices using the fully packed rectangular format, as this requires only n(n+1)/2 elements to be stored for a symmetric nxn matrix. So far, I am setting up the matrix in 'packed' format and transform it calling routine DTPTTF. However, this requires a second array. I would like to build my matrix directly in fully packed rectangular format (to save on space) - is there an 'addressing' function which will give me the position of the i,j-th element? or could somebody point me to the relevant formula?
to partly answer my own question: inspecting the source code of DTPTTF and the example given therein, I've worked out the adress for one of the four possible constellations (the only one I need), namely uplo ='L' and trans ='N'. below is my fortran function:
! ==================================== ! returns address for RFP format
integer function ijfprf( ii, jj, n ) ! for row jj and column ii
! ==================================== ! for UPLO = 'L' and TRANSR = 'N' only!
implicit none
integer, intent(in) :: ii, jj, n
integer :: i, j, k, n1, k1
if( ii <= jj ) then
i = ii; j = jj
else
i = jj; j = ii
end if
k = n/2
if( mod(n,2) == 0 ) then ! n even
n1 = n + 1
if( i <= k ) then
ijfprf = 1 + (i - 1) * n1 + j
else
ijfprf = ( j - k - 1 ) * n1 + i - k
end if
else ! n odd
k1 = k + 1
if( i > k1 ) then
ijfprf = ( j - k1 ) * n + i - k1
else
ijfprf = ( i - 1 ) * n + j
end if
end if
return
end function ijfprf

program runs differently depending on the use of cos or cosd( matlab functions)

My Matlab program works properly when the angles are in radians and thus I call cos and sin functions in the code below. When the angles are in degrees and thus I call cosd and sind, my program doesn't work as expected.
%Initial configuration of robot manipulator
%There are 7DOF( degrees of freedom) - 1 prismatic, 6 revolute
%vector qd represents these DOF
%indexes : d = gd( 1), q1 = qd( 2), ..., q6 = qd( 7)
qd( 1) = 1; % d = 1 m
qd( 2) = pi / 2; % q1 = 90 degrees
qd( 3 : 6) = 0; % q2 = ... = q6 = 0 degrees
qd( 7) = -pi / 2;
%Initial position of each joint - the tool is manipulated separately
%calculate sinusoids and cosines
[ c, s] = sinCos( qd( 2 : length( qd)));
and here is the sinCos code
function [ c, s] = sinCos( angles)
%takes a row array of angles in degrees and returns all the
%sin( angles( 1) + angles( 2) + ... + angles( i)) and
%cos( angles( 1) + angles( 2) + ... + angles( i)) where
%1 <= i <= length( angles)
sum = 0;
s = zeros( 1, length( angles)); % preallocate for speed
c = zeros( 1, length( angles));
for i = 1 : length( angles)
sum = sum + angles( i);
s( i) = sin( sum); % s( i) = sin( angles( 1) + ... + angles( i))
c( i) = cos( sum); % c( i) = cos( angles( 1) + ... + angles( i))
end % for
% end function
The whole program is ~ 700 lines, so I displayed only the part above. My program simulates the motion of a redundant robot that tries to reach a goal while avoiding two obstacles.
So, does my problem relates to cos and cosd? Do cos and cosd have a different behavior that affects my program? Or I have a bug in my program that is revealed?
By difference, do you mean something on the order of less than .00001? Because extremely small errors can be discounted due to floating point arithmetic errors. Computers are not able to accurately calculate decimal numbers with as much accuracy as they are able to store them. It is for this reason you should never directly compare two floating-point numbers; a range of error must be allowed for. You can read more about this here: http://en.wikipedia.org/wiki/Floating_point#Machine_precision_and_backward_error_analysis
If your error is greater than .0001 or so, you might consider searching for a bug in your program. If you are not already using matlab to convert units for you, consider doing so as I have found that it can eliminate many 'obvious' errors (and in some cases increase precision).