Handling decimals in somewhat complex mathHow to handle floating point number in Solidity?Decimals on ERC20 TokensCan you update contract token decimals and token name?Best practices for handling payment in smart contractsHow is a map initialised in memoryStoring complex data types in Eternal StorageSolidity Math: What's wrong with the functionHandling combinations without recursionHandling the String msg returned from revert() in solidityHow does delegatecall work from Solidity 0.5.0 onwards?Simple but important question: How to get the value of contract's state when using Metamask?
Managing libraries hosted on EmacsWiki
Does Lightning Network has concept of continuous stream of value?
Why does this sentence use 东西?
4 Layer PCB stack up
What LISP compilers and interpreters were available for 8-bit machines?
Why is the application of an oracle function not a measurement?
How hard would it be to convert a glider into an powered electric aircraft?
Select items in a list that contain criteria
Can a user sell my software (MIT license) without modification?
"Living" organ bank is it practical?
Company did not petition for visa in a timely manner. Is asking me to work from overseas, but wants me to take a paycut
Traffic law UK, pedestrians
Payment instructions from HomeAway look fishy to me
Do any instruments not produce overtones?
Why does VirtualBox crash macOS?
Why does NASA use higher frequencies even though they have worse Free Space Path Loss (FSPL)?
How to pass a regex when finding a directory path in bash?
Secure offsite backup, even in the case of hacker root access
How to retract the pitched idea from employer?
Building a road to escape Earth's gravity by making a pyramid on Antartica
Do manufacturers try make their components as close to ideal ones as possible?
Are go-arounds prohibited at St Barth (TFFJ)?
Does the "6 seconds per round" rule apply to speaking/roleplaying during combat situations?
SF novella separating the dumb majority from the intelligent part of mankind
Handling decimals in somewhat complex math
How to handle floating point number in Solidity?Decimals on ERC20 TokensCan you update contract token decimals and token name?Best practices for handling payment in smart contractsHow is a map initialised in memoryStoring complex data types in Eternal StorageSolidity Math: What's wrong with the functionHandling combinations without recursionHandling the String msg returned from revert() in solidityHow does delegatecall work from Solidity 0.5.0 onwards?Simple but important question: How to get the value of contract's state when using Metamask?
I'm a bit lost on what to do with the following calculation. The problem is that decimals are being round up/down, which obviously doesn't give me the result I desire.
int totalValue = 275000;
int percentage = 2;
for (uint i = 0; i < 30; i++)
totalValue += totalValue * percentage / 100;
With the above code, the result is:
498108
The expected result is:
498124.436
I know that normally you could simply use the following calculation to work with a predetermined amount of decimals like so:
value * 10**4 (4 decimals)
But I haven't gotten that to work in this case, often resulting in insanely high numbers due to the multiplication and division that "do not make sense" once I revert the above calculation using:
value / 10**4
Thank you very much for your time. Any help would be very much appreciated!
solidity contract-development contract-design contract-debugging
add a comment |
I'm a bit lost on what to do with the following calculation. The problem is that decimals are being round up/down, which obviously doesn't give me the result I desire.
int totalValue = 275000;
int percentage = 2;
for (uint i = 0; i < 30; i++)
totalValue += totalValue * percentage / 100;
With the above code, the result is:
498108
The expected result is:
498124.436
I know that normally you could simply use the following calculation to work with a predetermined amount of decimals like so:
value * 10**4 (4 decimals)
But I haven't gotten that to work in this case, often resulting in insanely high numbers due to the multiplication and division that "do not make sense" once I revert the above calculation using:
value / 10**4
Thank you very much for your time. Any help would be very much appreciated!
solidity contract-development contract-design contract-debugging
add a comment |
I'm a bit lost on what to do with the following calculation. The problem is that decimals are being round up/down, which obviously doesn't give me the result I desire.
int totalValue = 275000;
int percentage = 2;
for (uint i = 0; i < 30; i++)
totalValue += totalValue * percentage / 100;
With the above code, the result is:
498108
The expected result is:
498124.436
I know that normally you could simply use the following calculation to work with a predetermined amount of decimals like so:
value * 10**4 (4 decimals)
But I haven't gotten that to work in this case, often resulting in insanely high numbers due to the multiplication and division that "do not make sense" once I revert the above calculation using:
value / 10**4
Thank you very much for your time. Any help would be very much appreciated!
solidity contract-development contract-design contract-debugging
I'm a bit lost on what to do with the following calculation. The problem is that decimals are being round up/down, which obviously doesn't give me the result I desire.
int totalValue = 275000;
int percentage = 2;
for (uint i = 0; i < 30; i++)
totalValue += totalValue * percentage / 100;
With the above code, the result is:
498108
The expected result is:
498124.436
I know that normally you could simply use the following calculation to work with a predetermined amount of decimals like so:
value * 10**4 (4 decimals)
But I haven't gotten that to work in this case, often resulting in insanely high numbers due to the multiplication and division that "do not make sense" once I revert the above calculation using:
value / 10**4
Thank you very much for your time. Any help would be very much appreciated!
solidity contract-development contract-design contract-debugging
solidity contract-development contract-design contract-debugging
edited May 20 at 11:50
shane
2,6224932
2,6224932
asked May 20 at 10:11
NickNick
1235
1235
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
You need to multiply before calculations and divide after that:
int decimals = 4;
int totalValue = 275000;
int percentage = 2;
totalValue = totalValue * 10**decimals;
for (uint i = 0; i < 30; i++)
int AddValue = totalValue * percentage;
AddValue = AddValue / 100;
totalValue += AddValue;
totalValue = totalValue / 10**decimals;
EDIT: fixed line 5 and the percentage calculation
EDIT2: Actually you don't need to multiply the percentage and will get better results - fixed
Thank you for your answer! I was working on a solution that was similar to this, but I can see where I went wrong in several places. On line 5 I think it's missing an assignment, right? Also I keep getting "275000" as output with this example, but I haven't figured out why
– Nick
May 20 at 13:49
Wont the line "percentage = percentage / (100 * 10**decimals);" also get truncated to 0?
– Nick
May 20 at 13:55
1
made several errors in a hurry ... should be fixed now
– KNK
May 20 at 14:39
Awesome, that seems to work! I'll validate it properly as soon as possible. One more question though. This function will still return a rounded number, right? So would it be better to take out the last line and account for the fact that the last 4 digits are decimals wherever I'm calling the backend from? -or am I doing something wrong?
– Nick
May 20 at 14:47
1
There are no floating point numbers in Solidity (yet), so the number as always rounded at the end, but yes you can return the number as is and divide in the client to get a floating point result
– KNK
May 20 at 14:58
|
show 1 more comment
Generally speaking, in order to avoid data-loss (i.e., precision-loss) in an arithmetic computation, try to postpone every division as much as possible, without altering the expression.
More specifically with regards to your code, it appears that you are trying to compute the result of applying compound interest: 275000 * 1.02 ** 30.
You can do this very precisely in Solidity, by calculating (off-line) the exact value of 1.02 ** 30, and storing it scaled up to the level of precision that you desire.
Moreover, you won't even need those 30 iterations in order to achieve all that, so you can optimize your code here for both accuracy and performance.
For example:
uint256 INTEREST_N = 181136158410335375505681049921897;
uint256 INTEREST_D = 10000000000000000000000000000000;
uint256 totalValue = 275000 * INTEREST_N / INTEREST_D;
Of course, I'm aware of the fact that you most likely want the 275000 part as an input from the outside rather than a hard-coded value (in which case, you could just as well compute everything outside of the contract).
But assuming that the number of iterations and the compound interest percentage are both constant (30 and 2% in your case), you can do it using the numerator and denominator described above.
If either the number of iterations or the compound interest percentage is a variable, then instead of a single pair of numerator and denominator you can use an array of numerators and an array of denominators.
If both the number of iterations and the compound interest percentage are variables, then instead of a pair of arrays you can use a pair of tables.
I appreciate the answer and understand the gist of it, thank you! I'll come back to this solution once my understanding of the issue has improved.
– Nick
May 22 at 7:37
1
@Nick: NP. In your coding example, you could have simply used a constant (or two constants), so I suppose that this example does not represent what you're actually trying to achieve. As explained in my answer, I tend to guess that your intention is for one or more of these constants values (275000, 30 and 2%) to be an input variable. If you provide a description of the actual purpose, then I might be able to guide you through and suggest a scheme which will allow you to realize it while optimizing for both accuracy and performance (i.e., gas cost).
– goodvibration
May 22 at 7:42
That's awesome! In my case all three of those values are variables, so I figured I might as well send the result of 1.02**30 from the backend/caller. Also, the value of 275000 can contain decimals. At this point I'm not too sure how that will affect the calculation, but added "100000000000000000000000000000000 / (10**decimals);" to make the amount of decimals in the outcome variable.
– Nick
May 22 at 8:01
To add a more complete description of the variables with examples: the initial value (275000.5115 , max 4 decimals), interest rate (2.2152%, max 4 decimals) and amount of years (30, always a round number). To make it easier I can make sure there's always 4 decimals by padding zeroes.
– Nick
May 22 at 8:07
@Nick: Sorry, but in that case you can do the full calculation offline and just put the result hard-coded in your contract. There is no need for any code apart from that.
– goodvibration
May 22 at 9:37
|
show 7 more comments
The reason you are getting the value 498108 is because Solidity truncates divided values.
This means that if you divide 3/2, the result will be 1, not 1.5. Similarly, if you divide 11/3, the result will be 3, not 3.666.
With this in mind, the reason you are getting that final result is because a few of the loop results are being truncated.
So you're saying that it's not possible in any way? I'm aware of what's happening (actually I thought it was rounding it down/up, but you're saying it's truncating. Thanks for letting me know!), but I don't know how else to approach this to get the result I want.
– Nick
May 20 at 13:02
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "642"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fethereum.stackexchange.com%2fquestions%2f70898%2fhandling-decimals-in-somewhat-complex-math%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
You need to multiply before calculations and divide after that:
int decimals = 4;
int totalValue = 275000;
int percentage = 2;
totalValue = totalValue * 10**decimals;
for (uint i = 0; i < 30; i++)
int AddValue = totalValue * percentage;
AddValue = AddValue / 100;
totalValue += AddValue;
totalValue = totalValue / 10**decimals;
EDIT: fixed line 5 and the percentage calculation
EDIT2: Actually you don't need to multiply the percentage and will get better results - fixed
Thank you for your answer! I was working on a solution that was similar to this, but I can see where I went wrong in several places. On line 5 I think it's missing an assignment, right? Also I keep getting "275000" as output with this example, but I haven't figured out why
– Nick
May 20 at 13:49
Wont the line "percentage = percentage / (100 * 10**decimals);" also get truncated to 0?
– Nick
May 20 at 13:55
1
made several errors in a hurry ... should be fixed now
– KNK
May 20 at 14:39
Awesome, that seems to work! I'll validate it properly as soon as possible. One more question though. This function will still return a rounded number, right? So would it be better to take out the last line and account for the fact that the last 4 digits are decimals wherever I'm calling the backend from? -or am I doing something wrong?
– Nick
May 20 at 14:47
1
There are no floating point numbers in Solidity (yet), so the number as always rounded at the end, but yes you can return the number as is and divide in the client to get a floating point result
– KNK
May 20 at 14:58
|
show 1 more comment
You need to multiply before calculations and divide after that:
int decimals = 4;
int totalValue = 275000;
int percentage = 2;
totalValue = totalValue * 10**decimals;
for (uint i = 0; i < 30; i++)
int AddValue = totalValue * percentage;
AddValue = AddValue / 100;
totalValue += AddValue;
totalValue = totalValue / 10**decimals;
EDIT: fixed line 5 and the percentage calculation
EDIT2: Actually you don't need to multiply the percentage and will get better results - fixed
Thank you for your answer! I was working on a solution that was similar to this, but I can see where I went wrong in several places. On line 5 I think it's missing an assignment, right? Also I keep getting "275000" as output with this example, but I haven't figured out why
– Nick
May 20 at 13:49
Wont the line "percentage = percentage / (100 * 10**decimals);" also get truncated to 0?
– Nick
May 20 at 13:55
1
made several errors in a hurry ... should be fixed now
– KNK
May 20 at 14:39
Awesome, that seems to work! I'll validate it properly as soon as possible. One more question though. This function will still return a rounded number, right? So would it be better to take out the last line and account for the fact that the last 4 digits are decimals wherever I'm calling the backend from? -or am I doing something wrong?
– Nick
May 20 at 14:47
1
There are no floating point numbers in Solidity (yet), so the number as always rounded at the end, but yes you can return the number as is and divide in the client to get a floating point result
– KNK
May 20 at 14:58
|
show 1 more comment
You need to multiply before calculations and divide after that:
int decimals = 4;
int totalValue = 275000;
int percentage = 2;
totalValue = totalValue * 10**decimals;
for (uint i = 0; i < 30; i++)
int AddValue = totalValue * percentage;
AddValue = AddValue / 100;
totalValue += AddValue;
totalValue = totalValue / 10**decimals;
EDIT: fixed line 5 and the percentage calculation
EDIT2: Actually you don't need to multiply the percentage and will get better results - fixed
You need to multiply before calculations and divide after that:
int decimals = 4;
int totalValue = 275000;
int percentage = 2;
totalValue = totalValue * 10**decimals;
for (uint i = 0; i < 30; i++)
int AddValue = totalValue * percentage;
AddValue = AddValue / 100;
totalValue += AddValue;
totalValue = totalValue / 10**decimals;
EDIT: fixed line 5 and the percentage calculation
EDIT2: Actually you don't need to multiply the percentage and will get better results - fixed
edited May 20 at 15:14
answered May 20 at 13:38
KNKKNK
1716
1716
Thank you for your answer! I was working on a solution that was similar to this, but I can see where I went wrong in several places. On line 5 I think it's missing an assignment, right? Also I keep getting "275000" as output with this example, but I haven't figured out why
– Nick
May 20 at 13:49
Wont the line "percentage = percentage / (100 * 10**decimals);" also get truncated to 0?
– Nick
May 20 at 13:55
1
made several errors in a hurry ... should be fixed now
– KNK
May 20 at 14:39
Awesome, that seems to work! I'll validate it properly as soon as possible. One more question though. This function will still return a rounded number, right? So would it be better to take out the last line and account for the fact that the last 4 digits are decimals wherever I'm calling the backend from? -or am I doing something wrong?
– Nick
May 20 at 14:47
1
There are no floating point numbers in Solidity (yet), so the number as always rounded at the end, but yes you can return the number as is and divide in the client to get a floating point result
– KNK
May 20 at 14:58
|
show 1 more comment
Thank you for your answer! I was working on a solution that was similar to this, but I can see where I went wrong in several places. On line 5 I think it's missing an assignment, right? Also I keep getting "275000" as output with this example, but I haven't figured out why
– Nick
May 20 at 13:49
Wont the line "percentage = percentage / (100 * 10**decimals);" also get truncated to 0?
– Nick
May 20 at 13:55
1
made several errors in a hurry ... should be fixed now
– KNK
May 20 at 14:39
Awesome, that seems to work! I'll validate it properly as soon as possible. One more question though. This function will still return a rounded number, right? So would it be better to take out the last line and account for the fact that the last 4 digits are decimals wherever I'm calling the backend from? -or am I doing something wrong?
– Nick
May 20 at 14:47
1
There are no floating point numbers in Solidity (yet), so the number as always rounded at the end, but yes you can return the number as is and divide in the client to get a floating point result
– KNK
May 20 at 14:58
Thank you for your answer! I was working on a solution that was similar to this, but I can see where I went wrong in several places. On line 5 I think it's missing an assignment, right? Also I keep getting "275000" as output with this example, but I haven't figured out why
– Nick
May 20 at 13:49
Thank you for your answer! I was working on a solution that was similar to this, but I can see where I went wrong in several places. On line 5 I think it's missing an assignment, right? Also I keep getting "275000" as output with this example, but I haven't figured out why
– Nick
May 20 at 13:49
Wont the line "percentage = percentage / (100 * 10**decimals);" also get truncated to 0?
– Nick
May 20 at 13:55
Wont the line "percentage = percentage / (100 * 10**decimals);" also get truncated to 0?
– Nick
May 20 at 13:55
1
1
made several errors in a hurry ... should be fixed now
– KNK
May 20 at 14:39
made several errors in a hurry ... should be fixed now
– KNK
May 20 at 14:39
Awesome, that seems to work! I'll validate it properly as soon as possible. One more question though. This function will still return a rounded number, right? So would it be better to take out the last line and account for the fact that the last 4 digits are decimals wherever I'm calling the backend from? -or am I doing something wrong?
– Nick
May 20 at 14:47
Awesome, that seems to work! I'll validate it properly as soon as possible. One more question though. This function will still return a rounded number, right? So would it be better to take out the last line and account for the fact that the last 4 digits are decimals wherever I'm calling the backend from? -or am I doing something wrong?
– Nick
May 20 at 14:47
1
1
There are no floating point numbers in Solidity (yet), so the number as always rounded at the end, but yes you can return the number as is and divide in the client to get a floating point result
– KNK
May 20 at 14:58
There are no floating point numbers in Solidity (yet), so the number as always rounded at the end, but yes you can return the number as is and divide in the client to get a floating point result
– KNK
May 20 at 14:58
|
show 1 more comment
Generally speaking, in order to avoid data-loss (i.e., precision-loss) in an arithmetic computation, try to postpone every division as much as possible, without altering the expression.
More specifically with regards to your code, it appears that you are trying to compute the result of applying compound interest: 275000 * 1.02 ** 30.
You can do this very precisely in Solidity, by calculating (off-line) the exact value of 1.02 ** 30, and storing it scaled up to the level of precision that you desire.
Moreover, you won't even need those 30 iterations in order to achieve all that, so you can optimize your code here for both accuracy and performance.
For example:
uint256 INTEREST_N = 181136158410335375505681049921897;
uint256 INTEREST_D = 10000000000000000000000000000000;
uint256 totalValue = 275000 * INTEREST_N / INTEREST_D;
Of course, I'm aware of the fact that you most likely want the 275000 part as an input from the outside rather than a hard-coded value (in which case, you could just as well compute everything outside of the contract).
But assuming that the number of iterations and the compound interest percentage are both constant (30 and 2% in your case), you can do it using the numerator and denominator described above.
If either the number of iterations or the compound interest percentage is a variable, then instead of a single pair of numerator and denominator you can use an array of numerators and an array of denominators.
If both the number of iterations and the compound interest percentage are variables, then instead of a pair of arrays you can use a pair of tables.
I appreciate the answer and understand the gist of it, thank you! I'll come back to this solution once my understanding of the issue has improved.
– Nick
May 22 at 7:37
1
@Nick: NP. In your coding example, you could have simply used a constant (or two constants), so I suppose that this example does not represent what you're actually trying to achieve. As explained in my answer, I tend to guess that your intention is for one or more of these constants values (275000, 30 and 2%) to be an input variable. If you provide a description of the actual purpose, then I might be able to guide you through and suggest a scheme which will allow you to realize it while optimizing for both accuracy and performance (i.e., gas cost).
– goodvibration
May 22 at 7:42
That's awesome! In my case all three of those values are variables, so I figured I might as well send the result of 1.02**30 from the backend/caller. Also, the value of 275000 can contain decimals. At this point I'm not too sure how that will affect the calculation, but added "100000000000000000000000000000000 / (10**decimals);" to make the amount of decimals in the outcome variable.
– Nick
May 22 at 8:01
To add a more complete description of the variables with examples: the initial value (275000.5115 , max 4 decimals), interest rate (2.2152%, max 4 decimals) and amount of years (30, always a round number). To make it easier I can make sure there's always 4 decimals by padding zeroes.
– Nick
May 22 at 8:07
@Nick: Sorry, but in that case you can do the full calculation offline and just put the result hard-coded in your contract. There is no need for any code apart from that.
– goodvibration
May 22 at 9:37
|
show 7 more comments
Generally speaking, in order to avoid data-loss (i.e., precision-loss) in an arithmetic computation, try to postpone every division as much as possible, without altering the expression.
More specifically with regards to your code, it appears that you are trying to compute the result of applying compound interest: 275000 * 1.02 ** 30.
You can do this very precisely in Solidity, by calculating (off-line) the exact value of 1.02 ** 30, and storing it scaled up to the level of precision that you desire.
Moreover, you won't even need those 30 iterations in order to achieve all that, so you can optimize your code here for both accuracy and performance.
For example:
uint256 INTEREST_N = 181136158410335375505681049921897;
uint256 INTEREST_D = 10000000000000000000000000000000;
uint256 totalValue = 275000 * INTEREST_N / INTEREST_D;
Of course, I'm aware of the fact that you most likely want the 275000 part as an input from the outside rather than a hard-coded value (in which case, you could just as well compute everything outside of the contract).
But assuming that the number of iterations and the compound interest percentage are both constant (30 and 2% in your case), you can do it using the numerator and denominator described above.
If either the number of iterations or the compound interest percentage is a variable, then instead of a single pair of numerator and denominator you can use an array of numerators and an array of denominators.
If both the number of iterations and the compound interest percentage are variables, then instead of a pair of arrays you can use a pair of tables.
I appreciate the answer and understand the gist of it, thank you! I'll come back to this solution once my understanding of the issue has improved.
– Nick
May 22 at 7:37
1
@Nick: NP. In your coding example, you could have simply used a constant (or two constants), so I suppose that this example does not represent what you're actually trying to achieve. As explained in my answer, I tend to guess that your intention is for one or more of these constants values (275000, 30 and 2%) to be an input variable. If you provide a description of the actual purpose, then I might be able to guide you through and suggest a scheme which will allow you to realize it while optimizing for both accuracy and performance (i.e., gas cost).
– goodvibration
May 22 at 7:42
That's awesome! In my case all three of those values are variables, so I figured I might as well send the result of 1.02**30 from the backend/caller. Also, the value of 275000 can contain decimals. At this point I'm not too sure how that will affect the calculation, but added "100000000000000000000000000000000 / (10**decimals);" to make the amount of decimals in the outcome variable.
– Nick
May 22 at 8:01
To add a more complete description of the variables with examples: the initial value (275000.5115 , max 4 decimals), interest rate (2.2152%, max 4 decimals) and amount of years (30, always a round number). To make it easier I can make sure there's always 4 decimals by padding zeroes.
– Nick
May 22 at 8:07
@Nick: Sorry, but in that case you can do the full calculation offline and just put the result hard-coded in your contract. There is no need for any code apart from that.
– goodvibration
May 22 at 9:37
|
show 7 more comments
Generally speaking, in order to avoid data-loss (i.e., precision-loss) in an arithmetic computation, try to postpone every division as much as possible, without altering the expression.
More specifically with regards to your code, it appears that you are trying to compute the result of applying compound interest: 275000 * 1.02 ** 30.
You can do this very precisely in Solidity, by calculating (off-line) the exact value of 1.02 ** 30, and storing it scaled up to the level of precision that you desire.
Moreover, you won't even need those 30 iterations in order to achieve all that, so you can optimize your code here for both accuracy and performance.
For example:
uint256 INTEREST_N = 181136158410335375505681049921897;
uint256 INTEREST_D = 10000000000000000000000000000000;
uint256 totalValue = 275000 * INTEREST_N / INTEREST_D;
Of course, I'm aware of the fact that you most likely want the 275000 part as an input from the outside rather than a hard-coded value (in which case, you could just as well compute everything outside of the contract).
But assuming that the number of iterations and the compound interest percentage are both constant (30 and 2% in your case), you can do it using the numerator and denominator described above.
If either the number of iterations or the compound interest percentage is a variable, then instead of a single pair of numerator and denominator you can use an array of numerators and an array of denominators.
If both the number of iterations and the compound interest percentage are variables, then instead of a pair of arrays you can use a pair of tables.
Generally speaking, in order to avoid data-loss (i.e., precision-loss) in an arithmetic computation, try to postpone every division as much as possible, without altering the expression.
More specifically with regards to your code, it appears that you are trying to compute the result of applying compound interest: 275000 * 1.02 ** 30.
You can do this very precisely in Solidity, by calculating (off-line) the exact value of 1.02 ** 30, and storing it scaled up to the level of precision that you desire.
Moreover, you won't even need those 30 iterations in order to achieve all that, so you can optimize your code here for both accuracy and performance.
For example:
uint256 INTEREST_N = 181136158410335375505681049921897;
uint256 INTEREST_D = 10000000000000000000000000000000;
uint256 totalValue = 275000 * INTEREST_N / INTEREST_D;
Of course, I'm aware of the fact that you most likely want the 275000 part as an input from the outside rather than a hard-coded value (in which case, you could just as well compute everything outside of the contract).
But assuming that the number of iterations and the compound interest percentage are both constant (30 and 2% in your case), you can do it using the numerator and denominator described above.
If either the number of iterations or the compound interest percentage is a variable, then instead of a single pair of numerator and denominator you can use an array of numerators and an array of denominators.
If both the number of iterations and the compound interest percentage are variables, then instead of a pair of arrays you can use a pair of tables.
answered May 20 at 15:25
goodvibrationgoodvibration
5,11911127
5,11911127
I appreciate the answer and understand the gist of it, thank you! I'll come back to this solution once my understanding of the issue has improved.
– Nick
May 22 at 7:37
1
@Nick: NP. In your coding example, you could have simply used a constant (or two constants), so I suppose that this example does not represent what you're actually trying to achieve. As explained in my answer, I tend to guess that your intention is for one or more of these constants values (275000, 30 and 2%) to be an input variable. If you provide a description of the actual purpose, then I might be able to guide you through and suggest a scheme which will allow you to realize it while optimizing for both accuracy and performance (i.e., gas cost).
– goodvibration
May 22 at 7:42
That's awesome! In my case all three of those values are variables, so I figured I might as well send the result of 1.02**30 from the backend/caller. Also, the value of 275000 can contain decimals. At this point I'm not too sure how that will affect the calculation, but added "100000000000000000000000000000000 / (10**decimals);" to make the amount of decimals in the outcome variable.
– Nick
May 22 at 8:01
To add a more complete description of the variables with examples: the initial value (275000.5115 , max 4 decimals), interest rate (2.2152%, max 4 decimals) and amount of years (30, always a round number). To make it easier I can make sure there's always 4 decimals by padding zeroes.
– Nick
May 22 at 8:07
@Nick: Sorry, but in that case you can do the full calculation offline and just put the result hard-coded in your contract. There is no need for any code apart from that.
– goodvibration
May 22 at 9:37
|
show 7 more comments
I appreciate the answer and understand the gist of it, thank you! I'll come back to this solution once my understanding of the issue has improved.
– Nick
May 22 at 7:37
1
@Nick: NP. In your coding example, you could have simply used a constant (or two constants), so I suppose that this example does not represent what you're actually trying to achieve. As explained in my answer, I tend to guess that your intention is for one or more of these constants values (275000, 30 and 2%) to be an input variable. If you provide a description of the actual purpose, then I might be able to guide you through and suggest a scheme which will allow you to realize it while optimizing for both accuracy and performance (i.e., gas cost).
– goodvibration
May 22 at 7:42
That's awesome! In my case all three of those values are variables, so I figured I might as well send the result of 1.02**30 from the backend/caller. Also, the value of 275000 can contain decimals. At this point I'm not too sure how that will affect the calculation, but added "100000000000000000000000000000000 / (10**decimals);" to make the amount of decimals in the outcome variable.
– Nick
May 22 at 8:01
To add a more complete description of the variables with examples: the initial value (275000.5115 , max 4 decimals), interest rate (2.2152%, max 4 decimals) and amount of years (30, always a round number). To make it easier I can make sure there's always 4 decimals by padding zeroes.
– Nick
May 22 at 8:07
@Nick: Sorry, but in that case you can do the full calculation offline and just put the result hard-coded in your contract. There is no need for any code apart from that.
– goodvibration
May 22 at 9:37
I appreciate the answer and understand the gist of it, thank you! I'll come back to this solution once my understanding of the issue has improved.
– Nick
May 22 at 7:37
I appreciate the answer and understand the gist of it, thank you! I'll come back to this solution once my understanding of the issue has improved.
– Nick
May 22 at 7:37
1
1
@Nick: NP. In your coding example, you could have simply used a constant (or two constants), so I suppose that this example does not represent what you're actually trying to achieve. As explained in my answer, I tend to guess that your intention is for one or more of these constants values (275000, 30 and 2%) to be an input variable. If you provide a description of the actual purpose, then I might be able to guide you through and suggest a scheme which will allow you to realize it while optimizing for both accuracy and performance (i.e., gas cost).
– goodvibration
May 22 at 7:42
@Nick: NP. In your coding example, you could have simply used a constant (or two constants), so I suppose that this example does not represent what you're actually trying to achieve. As explained in my answer, I tend to guess that your intention is for one or more of these constants values (275000, 30 and 2%) to be an input variable. If you provide a description of the actual purpose, then I might be able to guide you through and suggest a scheme which will allow you to realize it while optimizing for both accuracy and performance (i.e., gas cost).
– goodvibration
May 22 at 7:42
That's awesome! In my case all three of those values are variables, so I figured I might as well send the result of 1.02**30 from the backend/caller. Also, the value of 275000 can contain decimals. At this point I'm not too sure how that will affect the calculation, but added "100000000000000000000000000000000 / (10**decimals);" to make the amount of decimals in the outcome variable.
– Nick
May 22 at 8:01
That's awesome! In my case all three of those values are variables, so I figured I might as well send the result of 1.02**30 from the backend/caller. Also, the value of 275000 can contain decimals. At this point I'm not too sure how that will affect the calculation, but added "100000000000000000000000000000000 / (10**decimals);" to make the amount of decimals in the outcome variable.
– Nick
May 22 at 8:01
To add a more complete description of the variables with examples: the initial value (275000.5115 , max 4 decimals), interest rate (2.2152%, max 4 decimals) and amount of years (30, always a round number). To make it easier I can make sure there's always 4 decimals by padding zeroes.
– Nick
May 22 at 8:07
To add a more complete description of the variables with examples: the initial value (275000.5115 , max 4 decimals), interest rate (2.2152%, max 4 decimals) and amount of years (30, always a round number). To make it easier I can make sure there's always 4 decimals by padding zeroes.
– Nick
May 22 at 8:07
@Nick: Sorry, but in that case you can do the full calculation offline and just put the result hard-coded in your contract. There is no need for any code apart from that.
– goodvibration
May 22 at 9:37
@Nick: Sorry, but in that case you can do the full calculation offline and just put the result hard-coded in your contract. There is no need for any code apart from that.
– goodvibration
May 22 at 9:37
|
show 7 more comments
The reason you are getting the value 498108 is because Solidity truncates divided values.
This means that if you divide 3/2, the result will be 1, not 1.5. Similarly, if you divide 11/3, the result will be 3, not 3.666.
With this in mind, the reason you are getting that final result is because a few of the loop results are being truncated.
So you're saying that it's not possible in any way? I'm aware of what's happening (actually I thought it was rounding it down/up, but you're saying it's truncating. Thanks for letting me know!), but I don't know how else to approach this to get the result I want.
– Nick
May 20 at 13:02
add a comment |
The reason you are getting the value 498108 is because Solidity truncates divided values.
This means that if you divide 3/2, the result will be 1, not 1.5. Similarly, if you divide 11/3, the result will be 3, not 3.666.
With this in mind, the reason you are getting that final result is because a few of the loop results are being truncated.
So you're saying that it's not possible in any way? I'm aware of what's happening (actually I thought it was rounding it down/up, but you're saying it's truncating. Thanks for letting me know!), but I don't know how else to approach this to get the result I want.
– Nick
May 20 at 13:02
add a comment |
The reason you are getting the value 498108 is because Solidity truncates divided values.
This means that if you divide 3/2, the result will be 1, not 1.5. Similarly, if you divide 11/3, the result will be 3, not 3.666.
With this in mind, the reason you are getting that final result is because a few of the loop results are being truncated.
The reason you are getting the value 498108 is because Solidity truncates divided values.
This means that if you divide 3/2, the result will be 1, not 1.5. Similarly, if you divide 11/3, the result will be 3, not 3.666.
With this in mind, the reason you are getting that final result is because a few of the loop results are being truncated.
edited May 20 at 18:46
answered May 20 at 11:48
shaneshane
2,6224932
2,6224932
So you're saying that it's not possible in any way? I'm aware of what's happening (actually I thought it was rounding it down/up, but you're saying it's truncating. Thanks for letting me know!), but I don't know how else to approach this to get the result I want.
– Nick
May 20 at 13:02
add a comment |
So you're saying that it's not possible in any way? I'm aware of what's happening (actually I thought it was rounding it down/up, but you're saying it's truncating. Thanks for letting me know!), but I don't know how else to approach this to get the result I want.
– Nick
May 20 at 13:02
So you're saying that it's not possible in any way? I'm aware of what's happening (actually I thought it was rounding it down/up, but you're saying it's truncating. Thanks for letting me know!), but I don't know how else to approach this to get the result I want.
– Nick
May 20 at 13:02
So you're saying that it's not possible in any way? I'm aware of what's happening (actually I thought it was rounding it down/up, but you're saying it's truncating. Thanks for letting me know!), but I don't know how else to approach this to get the result I want.
– Nick
May 20 at 13:02
add a comment |
Thanks for contributing an answer to Ethereum Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fethereum.stackexchange.com%2fquestions%2f70898%2fhandling-decimals-in-somewhat-complex-math%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown