I’m working on economic simulations and have used the following shortcut in my code:
Currency = Fixed(4)
Now I’ve run into a situation where I would like to change the precision in some cases. Redefining Currency before running the code has no effect. I guess the pre-compiler already replaced all occurrences of Currency with Fixed(4).
Is there a way that I can redefine Currency somehow before running my simulation code so that is has the desired effect? I guess I would have to define Currency in another way. If the possibility exists, what would the performance cost be?
Could you share a few more details of the problem?
Are you using FixedPointDecimals? If so, do you mean this?
Currency = FixedDecimal{Int, 4}
At least in the latest version of FixedPointDecimals (v0.4.3) it says the binding Fixed doesn’t exist.
Are you defining the type alias in a module? Then defining Currency outside of that module scope would have no effect (and redefining a variable in another module is not allowed).
At least in the REPL, changing the value of Currency works for me:
julia> using FixedPointDecimals
julia> Currency = FixedDecimal{Int, 4}
FixedDecimal{Int64, 4}
julia> function return_currency()
x = rand()
return Currency(x)
end
return_currency (generic function with 1 method)
julia> return_currency()
FixedDecimal{Int64,4}(0.3279)
julia> Currency = FixedDecimal{Int, 5}
FixedDecimal{Int64, 5}
julia> return_currency()
FixedDecimal{Int64,5}(0.55454)
If it is defined in a module, adding a “setter” method might work:
julia> module Simulation
using FixedPointDecimals
Currency = FixedDecimal{Int, 4}
function run_simulation()
x = rand()
return Currency(x)
end
function set_currency_precision(newPrecision)
global Currency
Currency = FixedDecimal{Int, newPrecision}
end
end
Main.Simulation
julia> Simulation.run_simulation()
FixedDecimal{Int64,4}(0.6850)
julia> Simulation.set_currency_precision(5)
FixedDecimal{Int64, 5}
julia> Simulation.run_simulation()
FixedDecimal{Int64,5}(0.13342)
Currency is indeed defined in a module. I tried the fix you mentioned but it didn’t work. I use Currency as a field type in some structs in the module.
# Simplified example
struct Balance
balance::Currency
end
Setting the precision to a different number results in an error when those structs are used:
I’m guessing that the following would fix the problem:
mutable struct Balance
value::FixedDecimal
Balance(value::Real) = new(Currency(value))
end
function set_balance(balance::Balance, value::Real)
balance.value = Currency(value)
end
What would the performance hit be on a solution like that? Applying it would mean quite some work on my code base since I’m using Currency all over the place.
Yes, if you set the field type of Balance to be Currency, it will be hard-coded to be whatever precision you had at that time. Changing field types of structs after their definition is not possible as far as I know.
I’d say it works, but using non-concrete field types usually leads to worse performance. See here for example.
It sounds like a cleaner solution might be to use a type parameter. If you don’t change the precision very often, I don’t think the performance would suffer (if you use a lot of different currency types, the cost of recompilation might go up – but when in doubt, benchmark).
struct Balance{C<:FixedDecimal}
balance::C
end
That makes the whole type carry the type C (currency type) with it. If the constructor is not too complicated, it should also work to infer the type without changing the code.
E.g. if you constructed a Balance object before with b = Balance(Currency(0.50)) then this line should still work after you redefine the module variable Currency with some setter function.