繁体   English   中英

应用于数组时最小的正乘数使数组成为整数

[英]Smallest positive multiplier that when applied to an array renders the array integral

给定一个n非负元素的数组,在C / C ++的任何库中是否有一个函数返回最小的正乘数 ,当应用于数组的每个元素时返回一个整数?

例如,如果n=2的数组是1.66667, 2.33333则乘数将是3.当我们将数组的每个元素乘以3时,我们得到5, 7 ,都是整数。

如果数组是8,10 ,则乘数将为0.5。 这将给我们4,5

(1)在任何一个众所周知的库中都有一个有效的函数,如boosteigen等?

(2)如果库中没有可用的东西,那么找出多个算法的有效算法是什么?

在一般情况下,您的问题没有很好的解决方案,因为这些值以具有有限精度的浮点格式存储,并且只能精确存储分母2的分数。 例如, 0.1 * 10可能不是您平台上的整数值。

如果从整数量计算数组中的值,则应将它们表示为具有足够大小的整数对的标准化分数,并计算其分母的最小公倍数。

如果您想要问题的近似解决方案,您可以指定epsilon的值,并手动设计解决方案。 我认为没有库函数来满足这个需求,但是一个强力解决方案很容易编写:

unsigned long long ullgcd(unsigned long long a, unsigned long long b) {
     /* compute the greatest common divisor using Euclid's elegant method */
     if (a < b)
         return ullgcd(b, a);
     else
     if (b == 0)
         return a;
     else
         return ullgcd(b, a % b);
}

double least_multiple(double *a, size_t n, double epsilon) {
    for (double mult = 1;; mult += 1) {
        size_t i;
        unsigned long long div = 0;
        for (i = 0; i < n; i++) {
            double d = fabs(a[i] * mult);
            unsigned long long v = round(d);
            if (fabs(v - d) > epsilon)
                break;
            div = ullgcd(v, div);
        }
        if (i == n)
            break;
    }
    /* mult is the smallest non zero integer that fits your goal.
       the smallest multiplier is obtained by dividing it 
       by the greatest common divisor of the resulting integer array.
    */
    return mult / div;
}

不是你指定的方式没有。 问题是十进制1.666672.33333没有这样的乘数:你假设的近似值来源于数学方面的任意舍入策略。

然后有浮点属性需要担心,所以你可以使用doublefloat来排除任何东西。

这里最好的选择是使用分数类来表示数字。 那么任何常见的乘数都会随着一些简单的数学而退出。

请参阅http://www.boost.org/doc/libs/1_64_0/libs/rational/index.html

看一下Rosetta Code的“将十进制数转换为有理数”。 由于我不熟悉C,我将C代码转换为Python(尽管我认为Python可能有一些相关的库)并添加了一些你可以轻松适应C的函数。如果分数转换中的分母是全部1.0 ,我们除以数字列表的最大公约数。 否则,我们会返回独特分母的产品。

import math
import operator

def f(arr):
  epsilon = 4
  fractions = [rat_approx(i, 16**epsilon) for i in arr]

  # The denominators in the fraction conversion are all 1.0
  if sum([denom for (num, denom) in fractions]) == len(fractions):
    return 1.0 / gcd_of_many([num for (num, denom) in fractions])
  else:
    # Otherwise, return the product of unique denominators
    return reduce(operator.mul, set([denom for (num, denom) in fractions]), 1)

def gcd(a, b):
  if a < b:
    return gcd(b, a)
  elif b == 0:
    return a;
  else:
    return gcd(b, a % b)

def gcd_of_many(arr):
  result = arr[0]
  for i in xrange(1, len(arr)):
    result = gcd(result, arr[i])
  return result

# Converted from
# https://rosettacode.org/wiki/Convert_decimal_number_to_rational#C
def rat_approx(f, md):
    #  a: continued fraction coefficients.
    h = [0, 1, 0]
    k = [1, 0, 0]
    n = 1
    neg = 0
    num = 0
    denom = 0

    if md <= 1:
      denom = 1
      num = f
      return num, denom

    if f < 0:
      neg = 1
      f = -f

    while f != math.floor(f):
      n <<= 1
      f *= 2

    d = f

    # continued fraction and check denominator each step
    for i in xrange(65):
        a = d // n if n else 0
        if i and not a:
          break

        x = d
        d = n
        n = x % n

        x = a;
        if k[1] * a + k[0] >= md:
            x = (md - k[0]) // k[1]
            if x * 2 >= a or k[1] >= md:
                i = 65
            else:
                break

        h[2] = x * h[1] + h[0]
        h[0] = h[1]
        h[1] = h[2]
        k[2] = x * k[1] + k[0]
        k[0] = k[1]
        k[1] = k[2]

    denom = k[1]
    num = -h[1] if neg else h[1]

    return (num, denom)

输出:

   f([8, 10])
=> 0.5
   f([1.66667, 2.33333])
=> 3.0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM