Obviously, there was a motive behind my asking about speed versus efficiency. At a minimum, I think there should be a
bit of an increase in certain parts of the code below due to the fact that the registers aren't being reloaded with all
of the previous variables each time a new denomination is required.
I guess I'm gonna finally have to sit down and learn how to use the debug and disassembler features. I've skated long
enough and I need to know how to do this.
I was reading up on those links that you provided Lerxst and that is some really interesting stuff.
So, are both the Win and Linux projects set up to be optimized for stuff like this automatically? I saw that whole program
optimization was off in the Win project, but I believe that the local was on (can't remember at the moment...)
I'd really like to get the division and mod operations as efficient as possible here (and in anything else that I submit.)
<For Example:>
[client.h]
Code:
#define CONVERSION_RATE 10
[client.cpp]
Code:
bool Client::TakeMoneyFromPP(uint64 copper, bool updateclient) {
if (!HasMoney(copper)) { return false; }
sint64 cur_copper = (static_cast<sint64>(m_pp.copper) - copper);
if (cur_copper < 0) {
copper = abs64(cur_copper);
cur_copper = ((CONVERSION_RATE - (copper % CONVERSION_RATE)) % CONVERSION_RATE);
copper = ((copper + cur_copper) / CONVERSION_RATE);
}
else { copper = 0; }
m_pp.copper = cur_copper;
sint64 cur_silver = (static_cast<sint64>(m_pp.silver) - copper);
if (cur_silver < 0) {
copper = abs64(cur_silver);
cur_silver = ((CONVERSION_RATE - (copper % CONVERSION_RATE)) % CONVERSION_RATE);
copper = ((copper + cur_silver) / CONVERSION_RATE);
}
else { copper = 0; }
m_pp.silver = cur_silver;
sint64 cur_gold = (static_cast<sint64>(m_pp.gold) - copper);
if (cur_gold < 0) {
copper = abs64(cur_gold);
cur_gold = ((CONVERSION_RATE - (copper % CONVERSION_RATE)) % CONVERSION_RATE);
copper = ((copper + cur_gold) / CONVERSION_RATE);
}
else { copper = 0; }
m_pp.gold = cur_gold;
sint64 cur_platinum = (static_cast<sint64>(m_pp.platinum) - copper);
if (cur_platinum < 0) {
#if (EQDEBUG>=5)
LogFile->write(EQEMuLog::Debug, "Client::TakeMoneyFromPP() %s's transaction resulted in a deficit of %i platinum",
GetName(), cur_platinum);
#endif
cur_platinum = 0;
}
m_pp.platinum = cur_platinum;
if (updateclient) { SendMoneyUpdate(); }
RecalcWeight();
Save();
return true;
}
I think that I'm using static_cast appropriately since I don't want to have an overflow issue with <m_pp.denomination> when I
subtract a <uint64> value from a <sint32>..especially when I know that the value of 'copper' WILL possibly exceed the maximum
negative (or minimum) <sint32> value.
I think that I also ran across something about '(unsigned)' being a free conversion. Would it be better to just use that instead
of invoking an abs64() call? Or would that return the wrong value on conversion?
I'm sure you gurus out there will have no problem following what I did here, but for anyone else wondering, basically, here is
what I did:
Code:
-> assign a temp variable [cur_denomination] to equal player currency [m_pp.denomination] minus debt [copper]
-> check to see if [cur_denom] is negative, which indicates there's not enough [cur_denom] to pay all the debt
[case:true]
-> reassign debt to [copper] <absolute/positive value>
-> "borrow" '10' and find result to clear current debt place value (second % C_R is for the case of '0'..don't want '10')
-> [cur_denom] added back to debt clears the place value..dividing by C_R converts to next denomination
[case:false]
-> set [copper] to zero '0' <clear all debt> .. [cur_denom] will be '0' or greater
-> reassign [m_pp.denom] to equal [cur_denom]
-> perform this test on each increasing denomination until all debt is payed off (if debt was zeroed, 'conversion' is pointless)
-> special check/log event in platinum in the case that something went awry
I can see why the person who coded the current implementation of this used multiplication. Using two division type operations as
much as I did in this can lead to much slower performance in non-optimized code..even if there are more calculations the other way...
(I think one of those links said as many as 41 cycles for a single, true-division operation.)
Anyways..it's open to suggestions.
Edit: I will look at other methods to avoid 'division' when I finish getting my system back up