c++ - 钳位到 "easy"数字

标签 c++ math user-interface graphing

所以我正在尝试制作一个图形应用程序,我正在使用 Desmos作为基础。

我正在努力解决的问题是 Desmos 处理轴 segmentation 的方式。当您放大或缩小比例时,比例总是在“简单”的简单数字上,例如 5、100、1000 等。所以我的问题是:如何通过任何级别的缩放来简化比例?

顺便说一句:使用 C++

最佳答案

我本来打算写一个描述来说明一般如何做到这一点,但后来我意识到代码可能比解释更容易。


最重要的一步:准确定义“简单”数字的含义。


示例 #1:1、2、4、8、16、32、64、128、...、1073741824、...

这些是二的幂。因此,一个简单的 ceil(log(x)/log(2.0)) 将解决它。


示例 #2:1、2、5、10、20、50、100、200、500、1000、2000、5000、10000 ...

有两个幂的混合,还有一些倍数。让我们仔细看看。

  • 其中的一个子集可以描述为十的幂。
    • 将公式更改为 ceil(log(x)/log(10.0)) 即可解决。
  • 对于每个 10 的幂,2.05.0 的倍数也是“简单数字”。
    • 在每次迭代中,在检查十的幂值之后,还要检查两个倍数。如果它适合其中一个值,则该值可以作为结果返回。

代码

以下代码只是为了解释概念。它效率不高 - 一个高效的版本应该使用对数在 O(1) 时间内获得结果。


#include <iostream>
#include <vector>
#include <limits>
#include <stdexcept>
#include <algorithm>

using namespace std;

double getNiceAxisLength(double value, double baseLength, double step, const std::vector<double>& subSteps)
{
    typedef std::vector<double>::const_iterator VecDoubleIter;
    if (value < 0.0)
    {
        throw std::invalid_argument("Error: value must be non-negative. Take absolute value if necessary.");
    }
    if (baseLength <= 0.0)
    {
        throw std::invalid_argument("Error: baseLength must be positive.");
    }
    if (step <= 1.0)
    {
        throw std::invalid_argument("Error: step must be strictly greater than 1.");
    }
    for (VecDoubleIter iter = subSteps.begin(); iter != subSteps.end(); ++iter)
    {
        double subStep = *iter;
        if (subStep <= 1.0 || subStep >= step)
        {
            throw std::invalid_argument("Error: each subStep must be strictly greater than 1, and strictly smaller than step.");
        }
    }
    // make ascending.
    std::vector<double> sortedSubSteps(subSteps.begin(), subSteps.end());
    std::sort(sortedSubSteps.begin(), sortedSubSteps.end());
    if (value <= baseLength)
    {
        return baseLength;
    }
    double length = baseLength;
    double terminateLength = numeric_limits<double>::max() / step;
    while (length < terminateLength)
    {
        for (VecDoubleIter iter = sortedSubSteps.begin(); iter != sortedSubSteps.end(); ++iter)
        {
            double subStep = *iter;
            if (value <= length * subStep)
            {
                return (length * subStep);
            }
        }
        double nextLength = length * step;
        if (value <= nextLength)
        {
            return nextLength;
        }
        length = nextLength;
    }
    return baseLength;
}

int main()
{
    double baseLength = 1.0;
    double step = 10.0;
    std::vector<double> subSteps;
    subSteps.push_back(2.5);
    subSteps.push_back(5);
    for (int k = 0; k < 1000; k += ((k >> 2) + 1))
    {
        double value = k;
        double result = getNiceAxisLength(value, baseLength, step, subSteps);
        cout << "k: " << value << " result: " << result << endl;
    }

    cout << "Hello world!" << endl;
    return 0;
}

输出

k: 0 result: 1
k: 1 result: 1
k: 2 result: 2.5
k: 3 result: 5
k: 4 result: 5
k: 6 result: 10
k: 8 result: 10
k: 11 result: 25
k: 14 result: 25
k: 18 result: 25
k: 23 result: 25
k: 29 result: 50
k: 37 result: 50
k: 47 result: 50
k: 59 result: 100
k: 74 result: 100
k: 93 result: 100
k: 117 result: 250
k: 147 result: 250
k: 184 result: 250
k: 231 result: 250
k: 289 result: 500
k: 362 result: 500
k: 453 result: 500
k: 567 result: 1000
k: 709 result: 1000
k: 887 result: 1000
Hello world!

世界,您好!

关于c++ - 钳位到 "easy"数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22445791/

相关文章:

Maven/第谷 SWTBot Eclipse RCP

c++ - 用数组初始化 std::string 的 vector

java - 我想将总购买量显示为 11.10 而不是 11.1

android - LibGDX - 颜色选择器

algorithm - 贝塞尔曲线在给定点的梯度

java - 操纵二的大幂的有效方法

C 控制台应用程序和 Qt gui 之间的通信

c++ - 无法链接 GLEW 库

c++ - 段错误 - 通过服务器将对象发送到客户端

c++ - 像结构成员一样访问 C++14 lambda 捕获