首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反求方程- JavaScript

反求方程- JavaScript
EN

Stack Overflow用户
提问于 2019-01-30 06:47:56
回答 4查看 3.2K关注 0票数 24

假设我有这个公式,例如:

代码语言:javascript
复制
function getExperience(level) {
  let a = 0;
  for (let x = 1; x < level; x += 1) {
    a += Math.floor(x + (200 * (2 ** (x / 3))));
  }

  return Math.floor(a / 4);
}


for (var i = 1; i < 100; i++) {
  console.log(`Level ${i}: ${getExperience(i)}`);
}

要获得50级所需的体验,您可以这样做:getExperience(50)

但是,你会如何扭转这种局面,并获得经验所需的水平呢?因此,getLevel(20010272)将输出50

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-01-30 10:55:38

简短回答

您可以使用4.328085 * Math.log(0.00519842 * xp + 1.259921045)作为相应级别的非常好的近似。

如果您需要一个确切的值,您可以遍历所有级别,直到找到所需的范围,就像在这个回答中一样。

长答案

微修改函数

我认为不可能为这个函数的逆找到一个精确的闭形表达式。不过,如果您稍微修改一下getExperience(level),应该是可能的。

  • 首先,您可以注意到x的增长比2 ** (x / 3)慢得多。
  • 然后,Math.floor对大量数据没有太大的影响。

所以让我们把它们移走!以下是稍加修改的函数:

代码语言:javascript
复制
function getExperienceEstimate(level) {
  let a = 0;
  for (let x = 1; x < level; x += 1) {
    a += 200 * (2 ** (x / 3));
  }
  return a / 4;
}

这种方法的优点是它现在是一个几何级数,因此可以不用任何循环计算和直接

代码语言:javascript
复制
function getExperienceEstimate(level) {
  let a = 50;
  let r = 2 ** (1 / 3);
  return a * (r**level - r) / (r - 1);
};

getExperienceEstimate(50)返回比getExperience(50)小0.0015%的20011971.993575357

逆函数

根据沃尔夫拉姆阿尔法,这是getExperienceEstimate的反函数

代码语言:javascript
复制
function getLevelEstimate(xp){
  let a = 50;
  let r = 2 ** (1 / 3);
  return Math.log(xp * (r - 1) / a + r) / Math.log(r);
};

由于精度损失较小,您可以进一步简化它:

代码语言:javascript
复制
function getLevelEstimate(xp){
  return 4.328085 * Math.log(0.00519842 * xp + 1.259921045)
};

这只是一个估计,但它工作得很好,不需要任何循环!

测试

对于20012272 XP,近似逆函数返回50.00006263463371,如果您想要找到确切的结果,这应该是一个很好的起点。

代码语言:javascript
复制
function getExperience(level) {
  let a = 0;
  for (let x = 1; x < level; x += 1) {
    a += Math.floor(x + (200 * (2 ** (x / 3))));
  }
  return Math.floor(a / 4);
}

function getLevelEstimate(xp){
  return 4.328085 * Math.log(0.00519842 * xp + 1.259921045)
};

for (var i = 1; i < 100; i++) {
  console.log(`Level ${i} (XP = ${getExperience(i)}). Estimated level : ${getLevelEstimate(getExperience(i))}`);
}

票数 42
EN

Stack Overflow用户

发布于 2019-01-30 07:20:04

您可以使用二进制搜索算法来避免循环所有可能性。

这里是一个我已经适应你的情况的例子。

首先需要创建一个数组来映射所有的level => experience,这个操作应该只执行一次,然后就不用再做了。

正如您在我的示例中所看到的,即使有1000个级别,您也不必迭代超过9次,无论您试图找到哪个级别。

代码语言:javascript
复制
// You first have to create an array with all your levels.
// This has to be done only ONCE because it's an expensive one!
const list = [];
for (let i = 1; i <= 1000; i++) {
  list[i] = getExperience(i);
}

function getExperience(level) {
  let a = 0;
  for (let x = 1; x < level; x += 1) {
    a += Math.floor(x + (200 * (2 ** (x / 3))));
  }

  return Math.floor(a / 4);
}

function getLevel(value) {
  // initial values for start, middle and end
  let start = 0
  let stop = list.length - 1
  let middle = Math.floor((start + stop) / 2)
  let iterations = 0;
  
  // While the middle is not what we're looking for and the list does not have a single item.
  while (list[middle] !== value && start < stop) {
    iterations++;
    if (value < list[middle]) {
      stop = middle - 1
    } else {
      start = middle + 1
    }

    // Recalculate middle on every iteration.
    middle = Math.floor((start + stop) / 2)
  }
  
  console.log(`${value} is Level ${middle} (Result found after ${iterations} iterations)`);
  return middle;
}

// Then you can search your level according to the experience
getLevel(0);
getLevel(72);
getLevel(20010272);
getLevel(getExperience(50));
getLevel(33578608987644589722);

票数 12
EN

Stack Overflow用户

发布于 2019-01-30 06:55:13

一个蛮力(但不优雅)的解决方案是,只需调用getExperience获取级别,直到达到比通过的exp需要更多经验的级别为止。

代码语言:javascript
复制
function getLevel(exp) {
  if (exp === 0) return 0;
  let level = 0;
  let calcExp = 0;
  while (exp > calcExp) {
    calcExp = getExperience(level);
    if (calcExp > exp) break;
    level++;
  }
  return level - 1;
}

console.log(getLevel(20012272)); // experience required for 50 on the dot
console.log(getLevel(20012270));
console.log(getLevel(20012274));
console.log(getLevel(0));

function getExperience(level) {
  let a = 0;
  for (let x = 1; x < level; x += 1) {
    a += Math.floor(x + (200 * (2 ** (x / 3))));
  }

  return Math.floor(a / 4);
}

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54434757

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档