Поскольку каждый и его собака публикуют перевод на другие популярные языки, вот моя версия для языка программирования Nimrod .Я также добавил обработку случаев, когда количество тиков меньше двух:
import math, strutils
const
defaultMaxTicks = 10
type NiceScale = object
minPoint: float
maxPoint: float
maxTicks: int
tickSpacing: float
niceMin: float
niceMax: float
proc ff(x: float): string =
result = x.formatFloat(ffDecimal, 3)
proc `$`*(x: NiceScale): string =
result = "Input minPoint: " & x.minPoint.ff &
"\nInput maxPoint: " & x.maxPoint.ff &
"\nInput maxTicks: " & $x.maxTicks &
"\nOutput niceMin: " & x.niceMin.ff &
"\nOutput niceMax: " & x.niceMax.ff &
"\nOutput tickSpacing: " & x.tickSpacing.ff &
"\n"
proc calculate*(x: var NiceScale)
proc init*(x: var NiceScale; minPoint, maxPoint: float;
maxTicks = defaultMaxTicks) =
x.minPoint = minPoint
x.maxPoint = maxPoint
x.maxTicks = maxTicks
x.calculate
proc initScale*(minPoint, maxPoint: float;
maxTicks = defaultMaxTicks): NiceScale =
result.init(minPoint, maxPoint, maxTicks)
proc niceNum(scaleRange: float; doRound: bool): float =
var
exponent: float ## Exponent of scaleRange.
fraction: float ## Fractional part of scaleRange.
niceFraction: float ## Nice, rounded fraction.
exponent = floor(log10(scaleRange));
fraction = scaleRange / pow(10, exponent);
if doRound:
if fraction < 1.5:
niceFraction = 1
elif fraction < 3:
niceFraction = 2
elif fraction < 7:
niceFraction = 5
else:
niceFraction = 10
else:
if fraction <= 1:
niceFraction = 1
elif fraction <= 2:
niceFraction = 2
elif fraction <= 5:
niceFraction = 5
else:
niceFraction = 10
return niceFraction * pow(10, exponent)
proc calculate*(x: var NiceScale) =
assert x.maxPoint > x.minPoint, "Wrong input range!"
assert x.maxTicks >= 0, "Sorry, can't have imaginary ticks!"
let scaleRange = niceNum(x.maxPoint - x.minPoint, false)
if x.maxTicks < 2:
x.niceMin = floor(x.minPoint)
x.niceMax = ceil(x.maxPoint)
x.tickSpacing = (x.niceMax - x.niceMin) /
(if x.maxTicks == 1: 2.0 else: 1.0)
else:
x.tickSpacing = niceNum(scaleRange / (float(x.maxTicks - 1)), true)
x.niceMin = floor(x.minPoint / x.tickSpacing) * x.tickSpacing
x.niceMax = ceil(x.maxPoint / x.tickSpacing) * x.tickSpacing
when isMainModule:
var s = initScale(57.2, 103.3)
echo s
Это версия с комментариями.Полный текст можно прочитать на GitHub , интегрированном в мой проект.