按比例将 Numpy 浮点数数组转换为整数(平衡化学方程式)

Convert Numpy array of floats to ints proportionately (balancing chemical equation)

我有一个平衡化学方程式的代码。唯一的问题是我想将最终解决方案(即 1D np 浮点数组)转换为整数。显然,我不能直接将它四舍五入到最接近的整数,那样会弄乱平衡。一种方法是将它与将浮点数转换为整数的数字相乘(类型无关紧要)。请参阅下面的示例。

>>> coeffs=equation_balancer(reactants=["H2","O2"], products=["H2O"])
>>> coeffs
{"H2": 1.0, "O2": 0.5, 'H2O1': 1.0}
>>> import numpy as np
>>>  np.asarray([i for i in coeffs.values()])
array([1. , 0.5, 1.])

如果最终数组乘以2,则可以删除分数(浮点数)。

PS 为了显示上面的示例,我改回 np,因为 equation_balancer 使用 scipy.linalg.solve 来平衡等式。

>>> np.asrray([i for i in coeffs.values()])*2
array([2., 1., 2.])

如何得到这个与数组相乘得到整数值数组的数字?数组的实际类型无关紧要。

一种方法是将数组与最高分母相乘,即 10 的倍数。然后找到最大公因数:

>>> c=np.asrray([i for i in coeffs.values()])*10
>>> factor = np.gcd.reduce(c.astype(int))
>>> factor
5
>>> c/factor
array([2., 1., 2.])

在上述情况下,找到由最高小数位数定义的 10*n 至关重要。我现在不知道如何编码。还有其他更合适的方法吗?任何帮助。

我对我的解决方案并不完全满意,但它似乎工作正常,让我知道你的想法,我实际上是将浮点数转换为字符串并计算小数点后的字符数,它会工作只要值始终为 float

import numpy as np

coeffs = {"H2": .1, "O2": 0.05, 'H2O1': .1}

n = max([len(str(i).split('.')[1]) for i in coeffs.values()])

c=np.array([i for i in coeffs.values()])*10**n
factor = np.gcd.reduce(c.astype(np.uint64))

print((c/factor).astype(np.uint64))

来源及其他解决方案: Easy way of finding decimal places

测试: 运行 一些可能的困难案例转换回来的例子

primes = [3,5,7,11,13,17,19,23,29,79] ## some prime numbers 

primes_over_1 = [1/i for i in primes]

for i in range(1, len(primes_over_1) - 1):
  coeffs = {"H2": primes_over_1[i-1], "O2": primes_over_1[i], 'H2O1': primes_over_1[i+1]}

  print('coefs: ', [a for a in coeffs.values()])

  n = max([len(str(a).split('.')[1]) for a in coeffs.values()])

  c=np.array([a for a in coeffs.values()])*10**n
  factor = np.gcd.reduce(c.astype(np.uint64))

  coeffs_asInt = (c/factor).astype(np.uint64)

  print('as int:', coeffs_asInt)

  coeffs_back = coeffs_asInt.astype(np.float64)*(factor/10**n)

  coeffs_back_str = ["{0:.16g}".format(a) for a in coeffs_back] 
  print('back:  ', coeffs_back_str)

  print('########################################################\n')

输出:

coefs:  [0.3333333333333333, 0.2, 0.14285714285714285]
as int: [8333333333333333 5000000000000000 3571428571428571]
back:   ['0.3333333333333334', '0.2', '0.1428571428571428']
########################################################

coefs:  [0.2, 0.14285714285714285, 0.09090909090909091]
as int: [5000000000000000 3571428571428571 2272727272727273]
back:   ['0.2', '0.1428571428571428', '0.09090909090909093']
########################################################

coefs:  [0.14285714285714285, 0.09090909090909091, 0.07692307692307693]
as int: [14285714285714284  9090909090909092  7692307692307693]
back:   ['0.1428571428571428', '0.09090909090909093', '0.07692307692307694']
########################################################

coefs:  [0.09090909090909091, 0.07692307692307693, 0.058823529411764705]
as int: [2840909090909091 2403846153846154 1838235294117647]
back:   ['0.09090909090909091', '0.07692307692307693', '0.05882352941176471']
########################################################

coefs:  [0.07692307692307693, 0.058823529411764705, 0.05263157894736842]
as int: [2403846153846154 1838235294117647 1644736842105263]
back:   ['0.07692307692307693', '0.05882352941176471', '0.05263157894736842']
########################################################

coefs:  [0.058823529411764705, 0.05263157894736842, 0.043478260869565216]
as int: [1838235294117647 1644736842105263 1358695652173913]
back:   ['0.05882352941176471', '0.05263157894736842', '0.04347826086956522']
########################################################

coefs:  [0.05263157894736842, 0.043478260869565216, 0.034482758620689655]
as int: [6578947368421052 5434782608695652 4310344827586207]
back:   ['0.05263157894736842', '0.04347826086956522', '0.03448275862068966']
########################################################

coefs:  [0.043478260869565216, 0.034482758620689655, 0.012658227848101266]
as int: [21739130434782608 17241379310344828  6329113924050633]
back:   ['0.04347826086956522', '0.03448275862068966', '0.01265822784810127']
########################################################

这似乎有效:

(感谢 this SO answer 如何将浮点数转换为“最小”整数分子和整数分母的元组——而不是一些非常大的分子和分母)

import numpy as np
from fractions import Fraction

# A configurable param.
# Keep this small to avoid frekish large results.
# Increase it only in rare cases where the coeffs
# span a "huge" scale.
MAX_DENOM = 100

fractions = [Fraction(val).limit_denominator(MAX_DENOM)
             for val in coeffs.values()]
ratios = np.array([(f.numerator, f.denominator) for f in fractions])
# As an alternative to the above two statements, uncomment and use
# below statement for Python 3.8+
# ratios = np.array([Fraction(val).limit_denominator(MAX_DENOM).as_integer_ratio()
#                    for val in coeffs.values()])

factor = np.lcm.reduce(ratios[:,1])
result = [round(v * factor) for v in coeffs.values()]

# print
result

coeffs = {"H2": 1.0, "O2": 0.5, 'H2O1': 1.0}的输出:

[2, 1, 2]

coeffs = {"H2": 0.5, "N2":0.5, "O2": 1.5, "H1N1O3":1.0}的输出:

[1, 1, 3, 2]

coeffs = {"H2": 1.0, "O3": (1/3), "H2O1":1.0}的输出:

[3, 1, 3]

coeffs = {"H4": 0.5, "O7": (1/7), "H2O1":1.0}的输出:

[7, 2, 14]

coeffs = {"H2": .1, "O2": 0.05, 'H2O1': .1}的输出:

[2, 1, 2]