Forgottenserver: incorrect return values in vocation:getRequiredSkillTries(skill, level)

Created on 13 Nov 2020  路  5Comments  路  Source: otland/forgottenserver

tl;dr: It's a rounding error that seems to be happening in vocation.cpp only

Before creating an issue, please ensure:

  • [x] This is a bug in the software that resides in this repository, and not a
    support matter (use https://otland.net/forums/support.16/ for support)
  • [x] This issue is reproducible without changes to the C++ code in this repository

Steps to reproduce (include any configuration/script required to reproduce)

  1. print(Vocation(3):getRequiredSkillTries(SKILL_AXE, 100))
  2. put actual formula instead of c++ one

lua: print(50 * 1.2^(100 - 11))
wolframalpha: type 50 * 1.2^(100 - 11) in formula box (wolframalpha.com)
mysql: type select FLOOR(50 * POW(1.2,(100 - 11))) as '' in phpmyadmin

Expected behaviour

return value should be 557315218 or 557315218.7056

Actual behaviour

return value in tfs is 557317189

Environment

Windows 7, compilation mode 64-bit release

bug

Most helpful comment

All 5 comments

I have been doing tests by compiling the server several times but the returned value is always wrong.

I did some tests outside the compiler and the result was correct, as shown in the following image:
image

I think the problem lies in some configuration present in the compiler regarding the function: std::pow

I tested it on double only and it returned correct values. However, when I reproduced tfs code, it showed incorrect value again so the mistake must be in the code itself.

#include <iostream>
#include<math.h>
#include<map>

using namespace std;

std::map<uint32_t, uint32_t> cacheSkill[2];

uint64_t getReqSkillTries(uint16_t level)
{
    float skillmult = 1.2f;
    uint32_t skillBase = 50;
    auto it = cacheSkill[1].find(level);
    if (it != cacheSkill[1].end()) {
        return it->second;
    }

    uint64_t tries = static_cast<uint64_t>(skillBase * pow(static_cast<double>(skillmult), level - 11));
    cacheSkill[1][level] = tries;
    return tries;
}

int main() {
    uint64_t result = getReqSkillTries(100);
    cout << result;
    cin.get();

    return 0;
}

It must be some compiler configuration, some decimal limiter or something like that, I have not yet started looking for a solution, but it is what I suppose.

it's a problem with cast from float to double unrelated to the configuration (this was tested in codeblocks on a cpp file, not even a project)

when I use double skillmult = 1.2; instead of float skillmult = 1.2f; it works correctly

btw

    double skillmult = 1.2;
    float skillmult2 = 1.2f;

    cout << skillmult << " " << skillmult2 << " " << (static_cast<double>(skillmult2) == skillmult) << endl;

output: 1.2 1.2 0

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zeeb92 picture zeeb92  路  4Comments

conde2 picture conde2  路  6Comments

TwistedScorpio picture TwistedScorpio  路  5Comments

EPuncker picture EPuncker  路  3Comments

GoularPink picture GoularPink  路  4Comments