Search code examples
c++mathlogarithm

Calculate number of points per decade from logarithmic range


I have a range of base-10 logarithmically spaced points and I need to calculate the #points-per-decade for the points.

Based on this section from wikipedia we have #decades = log10(start / stop). From this we should be able to calculate #points-per-decade as #points / #decades. However this does not give the right answer. Here is a short program I've been using to test this method:

#include <iostream>
#include <algorithm>
#include <vector>

#include <cmath>
#include <float.h>

class GenLog {
public:
  GenLog(double start, double step) : curVal(start), step(step) {
    m = 1.0 / step;
    b = std::log10(start);
    stepi = 0;
  };

  double operator()() {
    ++stepi;
    double arg = m*stepi+b;

    if (arg < DBL_MAX_10_EXP) {
      curVal += pow(10.0, arg) - curVal;
    } else {
      curVal = DBL_MAX;
    }

    return curVal;
  }
private:
  double step, stepi, curVal, m, b;
};

int main(int argc, char *argv[])
{
  if (argc < 5) {
    std::cout << "Wrong number of args: format is [start] [stop] [points-per-decade] [size]\n";
    return -1;
  }
  
  double start = atof(argv[1]);
  double stop = atof(argv[2]);
  double ppd = atof(argv[3]);
  int size = atoi(argv[4]);
  std::vector<double> vals;

  vals.push_back(start);
  // generate total number of points - 2 (excluding endpoints, GenLog takes in
  // starting freq, and #point/dec
  std::generate_n(std::back_inserter(vals), size - 2, GenLog(start, ppd));
  vals.push_back(stop);

  for (auto i : vals) {
    std::cout << i << " ";
  }

  std::cout << "\n---TEST BACKWARDS PPD---\n";
  std::cout << "ppd: " << ppd << "\t          " << (vals.size()) / std::log10(*std::prev(vals.end()) / vals.front()) << "\n";
  return 0;
}

Example output: This generates a logarithmically spaced series of points from 1 to 10.1681 with 13 points per decade for a total of 15 points--although in principal you only need the starting point, and the points per decade to generate the next logarithmic point in the series.

As you can see the resulting numbers (13 and 14.8922) are not the same when they should be.

./so 1.0 10.1681 13 15
1 1.19378 1.4251 1.70125 2.03092 2.42446 2.89427 3.45511 4.12463 4.92388 5.87802 7.01704 8.37678 10 10.1681 
---TEST BACKWARDS PPD---
ppd: 13           14.8922

based on my testing so far I do not think it is anything like an off-by-one error. Perhaps the calculations for #points-per-decade is conceptually incorrect? If so what is the correct way of calculating it?


Solution

  • My way of calculating #points-per-decade was incorrect

    So based on the last equation in the calculations section of the wikipedia article we have:

    step-size = 10^(1 / #points-per-decade)

    since we know the step-size we can re-arrange to

    1/#points-per-decade * ln(10)=ln(step-size)

    and finally solve for #points-per-decade

    #points-per-decade = ln(10) / ln(step-size)