如何找到两个值之间的分布

how to find distribution between two values

假设我有一张 210mm x 297mm (A4) 的页面。它的每边打印边距为 5 毫米。 我想打印 1cm x 1cm 的正方形来填充页面。每个正方形都有特定的边距,比如向右 1 毫米,向底部 2 毫米。 现在计算我能得到多少方块就很容易了:

( 210 - 10 ) / ( 10 + 1 ) = 18.181...

( 297 - 10 ) / ( 10 + 2 ) = 23.916...

所以 23 行 18 列的正方形适合我的页面。


现在我希望第一行正方形为 1cm x 1cm,最后一行为 5mm x 5mm。

但中间的所有行都应填满 < 1 厘米到 > 5 毫米的行。尺寸从上到下递减。

如何找到行数和每行的平方大小?


我能想到的最好的,但需要尝试以下步骤:

const heightAvailable = 287;
const maxSizeElement  = 10;
const minSizeElement  = 5;
const marginBottom    = 2;
const step            = 0.15;

function getElementsArray(availableLeft, minElement, maxElement, margin, step) {
  const elementsArray = [];
  elementsArray.push(minElement);
  elementsArray.push(maxElement);

  while(isSizeLeft(availableLeft, minElement, maxElement, margin)) {
    minElement+=step;
    maxElement-=step;
    elementsArray.push(Number((minElement).toFixed(1)));
    elementsArray.push(Number((maxElement).toFixed(1)));

    availableLeft = getSizeLeft(availableLeft, minElement, maxElement, margin);
  }

  return elementsArray.sort(function(a,b) { return b - a;});;
}

function isSizeLeft(total, minElement, maxElement, margin) {
  return 0 < total - (maxElement+margin) - (minElement+margin);
}

function getSizeLeft(total, minElement, maxElement, margin) {
  return total - (maxElement+margin) - (minElement+margin);
}

哪个returns:

array(32) {
  [0]=>
  int(10)
  [1]=>
  float(9.9)
  [2]=>
  float(9.7)
  [3]=>
  float(9.6)
  [4]=>
  float(9.4)
  [5]=>
  float(9.3)
  [6]=>
  float(9.1)
  [7]=>
  float(9)
  [8]=>
  float(8.8)
  [9]=>
  float(8.7)
  [10]=>
  float(8.5)
  [11]=>
  float(8.4)
  [12]=>
  float(8.2)
  [13]=>
  float(8.1)
  [14]=>
  float(7.9)
  [15]=>
  float(7.8)
  [16]=>
  float(7.3)
  [17]=>
  float(7.1)
  [18]=>
  float(7)
  [19]=>
  float(6.8)
  [20]=>
  float(6.7)
  [21]=>
  float(6.5)
  [22]=>
  float(6.4)
  [23]=>
  float(6.2)
  [24]=>
  float(6.1)
  [25]=>
  float(5.9)
  [26]=>
  float(5.8)
  [27]=>
  float(5.6)
  [28]=>
  float(5.5)
  [29]=>
  float(5.3)
  [30]=>
  float(5.2)
  [31]=>
  int(5)
}

这是一个使用 Python 和 numpy 进行计算的解决方案。转换为 javascript 应该相当容易,尽管使用了更多的代码。最“复杂”的函数是 np.linspace 它将一个范围划分为 n 个均匀分布的值:

import numpy as np

heightAvailable = 287
maxSizeElement = 10
minSizeElement = 5
marginBottom = 2

for n in range(2, 100):
    sizes = np.linspace(10, 5, n)  # n evenly distributed numbers between 10 and 5 (both included)
    total_space = np.sum(sizes) + (n - 1) * marginBottom
    print(f"With {n} rows; total_space: {total_space:.2f} mm")
    if total_space > heightAvailable:
        sizes = np.linspace(10, 5, n - 1)
        total_space = np.sum(sizes) + (n - 2) * marginBottom
        print(f"Use {n - 1} rows; total_space: {total_space:.1f} mm\nsizes:")
        print(sizes)
        break

输出:

With 2 rows; total_space: 17.00 mm
With 3 rows; total_space: 26.50 mm
With 4 rows; total_space: 36.00 mm
...
With 28 rows; total_space: 264.00 mm
With 29 rows; total_space: 273.50 mm
With 30 rows; total_space: 283.00 mm
With 31 rows; total_space: 292.50 mm
Use 30 rows; total_space: 283.0 mm
sizes:
[10.          9.82758621  9.65517241  9.48275862  9.31034483  9.13793103
  8.96551724  8.79310345  8.62068966  8.44827586  8.27586207  8.10344828
  7.93103448  7.75862069  7.5862069   7.4137931   7.24137931  7.06896552
  6.89655172  6.72413793  6.55172414  6.37931034  6.20689655  6.03448276
  5.86206897  5.68965517  5.51724138  5.34482759  5.17241379  5.        ]

对于更数学的方法,您可以用符号计算所有内容,例如使用 Python 的 sympy。请注意,小方块的单个大小是第一个和最后一个大小之间的插值。可以使用三角数的公式并求解二次方程“手动”计算公式,或者让 sympy 完成工作:

from sympy import symbols, Sum, Eq, solve

heightAvailable, maxSizeElement, minSizeElement, marginBottom = symbols(
    'heightAvailable maxSizeElement minSizeElement marginBottom')

i, n = symbols('i n')
total = Sum((i - 1) / (n - 1) * maxSizeElement + (n - 1 - (i - 1)) / (n - 1) * minSizeElement,
            (i, 1, n)) + (n - 1) * marginBottom
sol = solve(Eq(total.simplify(), heightAvailable), n)
print(sol)
print(sol[0].subs({heightAvailable: 287, maxSizeElement: 10, minSizeElement: 5, marginBottom: 2}).evalf())

输出:

[2*(heightAvailable + marginBottom)/(2*marginBottom + maxSizeElement + minSizeElement)]
30.4210526315789