我正在尝试优化算法,但我想不出一种更好的方法来实现它。

一个输入(时钟频率值)将通过乘法器和除数的组合。

  • 目的是找到在给定输入的情况下将产生所需输出值的乘数和除数值的集合。



  • 我当前的(天真?)实现是:
    #define PRE_MIN 10000000
    #define PRE_MAX 20000000
    
    // Available values of the multipliers and divisors.
    uint8_t mult1_vals[] = {1, 2};
    uint8_t mult2_vals[] = {1, 2, 4, 8};
    uint8_t mult3_vals[] = {3, 5, 7};
    uint8_t div1_vals[] = {1, 2, 4};
    uint8_t div2_vals[] = {1, 2, 4, 8};
    
    bool exists_mults_divs(uint32_t in_val, uint32_t out_val)
    {
        uint8_t i_m1, i_m2, i_m3, i_d1, i_d2;
        uint32_t calc_val;
    
        for (i_m1 = 0; i_m1 < sizeof(mult1_vals); i_m1++) {
        for (i_m2 = 0; i_m2 < sizeof(mult2_vals); i_m2++) {
        for (i_m3 = 0; i_m3 < sizeof(mult3_vals); i_m3++) {
        for (i_div1 = 0; i_div1 < sizeof(div1_vals); i_div1++) {
    
        calc_val = in_val * (mult1_vals[i_m1] * mult2_vals[i_m2] *
                             mult3_vals[i_m3] / div1_vals[i_div1]);
        if ((calc_val <= PRE_MIN) || (calc_val > PRE_MAX))
            continue; // Can this be refactored?
    
        for (i_div2 = 0; i_div2 < sizeof(div2_vals); i_div2++) {
            calc_val /= div2_vals[i_div2];
            if (calc_val == out_val)
                return true;
        }
    
        }
        }
        }
        }
    
        // No multiplier/divisor values found to produce the desired out_val.
        return false;
    }
    

    有什么办法可以优化这个?还是使用一些算法方法?

    我正在使用C,但是任何类型的伪代码都可以。

    编辑:
    一些例子可以澄清。这将返回true:
    exists_mults_divs(2000000, 7000000); // in=2000000, out=7000000
    // Iterating over the values internally:
    // 1. in * 1 * 1 * 3 / 1 = 6000000
    //    6000000 is not within PRE_MIN/MAX range of 10-20000000.
    // 2. in * 1 * 1 * 5 / 1 = 10000000 is within range, try varying div2
    //    2a. div2=1 => 10000000 / 1 = 10000000 != 7000000 not desired out
    //    2b. div2=2 => 10000000 / 2 = 50000000 != 7000000
    //    etc.
    // 3. in * 1 * 1 * 7 / 1 = 7000000 not within range
    // etc.
    // 4. in * 1 * 2 * 7 / 1 = 14000000 is within range, try varying div2
    //    4a. div2=1 => 14000000 / 1 != 7000000
    //    4b. div2=2 => 14000000 / 2 == 7000000 IS desired out
    //
    // RETURN RESULT:
    //    TRUE since a 2000000 in can generate a 7000000 out with
    //    mult1=1, mult2=2, mult3=7, div1=1, div2=2
    

    这将返回false:
    exists_mults_divs(2000000, 999999999);
    

    因为没有除数和乘数与可用值的组合,否则将导致获得999999999

    最佳答案

    重新排序公式,我们有

    OutClk/(Mult1*Mult2*Mult3) = InClk/(Div1*Div2);
    
  • 看一下Mult1 = {1, 2}Mult2 = {1, 2, 4, 8},请注意,它们都是2的幂。
  • 同样,对于Div1Div2,它们也具有2的幂。
  • Mult3 = {3,5,7},它们都是素数。

  • 因此,我们需要做的是将InClk和OutClk除以它们最大的公共(public)除法器(GCD)
    int g = gcd(InClk, OutClk);
    
    InClk /= g;
    
    OutClk/= g;
    

    为了InClk == OutClk,我们需要使InClk/gOutClk/g都等于1。

    分割后剩下的InClk中,我们尝试将其除以每个div_vals中可以分割InClk的最大元素。 (因为div_vals中的每个元素都是2的幂,所以我们需要选择最大的元素)。
    for(int i = sizeof(div1_vals) - 1; i>= 0; i--)
        if(InClk % div1_vals[i] == 0){
            InClk/= div1_vals[i];
            break;
        }
    
    for(int i = sizeof(div2_vals) - 1; i>= 0; i--)
        if(InClk % div2_vals[i] == 0){
            InClk/= div2_vals[i];
            break;
        }
    

    对于OutClk同样
    for(int i = sizeof(mul1_vals) - 1; i>= 0; i--)
        if(OutClk % mul1_vals[i] == 0){
            OutClk/= mul1_vals[i];
            break;
        }
    ....
    

    最后,如果是InClk == 1 and OutClk == 1,则返回true,否则返回false。

    时间复杂度为 O(n),其中n是所有mul1_vals中元素的最大数量,...

    关于c++ - 计算乘数和除数值的优化算法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30657180/

    10-09 03:05