在C

时间:2017-02-19 04:11:02

标签: c

我必须编写一个程序,它接受两个正整数, start end ,其中(1&lt; start &lt; < EM>端)。然后程序将在此范围内[开始结束]并计算3的幂数。

因此,例如,如果 start 为2且 end 为10,则输出为2.(3和9为3的幂)。

以下是我的代码:

#include <stdio.h>
#include <math.h>

int main(void) {

    int start, end, i, count = 0;

    printf("Enter start and end: ");
    scanf("%d %d", &start, &end);

    for (i = start; i <= end; i++) {
        if ((log(i) / log(3)) == floor((log(i) / log(3)))) {
            printf("%d\n", i);
            count++;
        }
    }
    printf("Answer = %d\n", count);

    return 0;
}

但是,当我尝试运行其中一个测试用例[3,1000]时,输出为5,当它应为6时。

3
9
27
81
729
Answer = 5

缺少243号码。我的代码有问题吗?

5 个答案:

答案 0 :(得分:5)

问题是您正在使用浮点数的精确比较。具体来说,这里:

if ((log(i)/log(3)) == floor((log(i)/log(3))))

由于log()floor()返回double,您在没有任何容差的情况下比较了两个无法以这种方式进行比较的值。

How should I do floating point comparison?

答案 1 :(得分:1)

您的直接问题与浮点数的不精确有关,这一点通常在网上有详细记录,包括用于解决该问题的各种方法。

但是, >这样做的效率更高,只涉及 整数。

不是通过你的范围内的数字来寻找使用浮点运算的3的幂,你最好通过三次幂(使用整数乘法)来寻找你范围内的数字。

在伪代码中,这将是:

powerOfThree = 1
while powerOfThree <= endRange:
    if powerOfThree >= startRange:
        print powerOfThree
    powerOfThree = powerOfThree * 3

你甚至可以通过为powerOfThree选择一个更合适的起始值来使更多更有效率,但是,因为在64位数字中只有40多个3的幂,所以&# 39;可能是浪费时间。

当从伪代码转换为更具体的C时,您不幸会遇到该语言中数据类型的限制,特别是乘法可能导致溢出的事实。

有多种方法可以避免这种情况,例如检测它即将发生并提前退出循环。

下面给出了您需要的功能,一个处理此问题的功能,以及一些可用于验证它的测试代码。

#include <stdio.h>
#include <limits.h>

// I hate typing :-)

typedef unsigned long ULONG;
typedef unsigned int UINT;

static UINT countPowersOfThreeBetween (ULONG low, ULONG high) {
    // Catch invalid params, just exit with zero.

    if (low > high) return 0;

    // Go through all powers of three.

    ULONG powerOfThree = 1;
    UINT count = 0;
    do {
        // If within your range, count it.

        if ((powerOfThree >= low) && (powerOfThree <= high)) {
            count++;
            // printf ("DEBUG: got %lu\n", powerOfThree);
        }

        // Early exit if about to overflow.

        if (ULONG_MAX / powerOfThree < 3) break;

        // Advance to next power and continue if within range.

        powerOfThree *= 3;

    } while (powerOfThree <= high);

    // Notify caller of count.

    return count;
}

// Test function to make test suite easier.

static void testRange (ULONG low, ULONG high) {
    UINT count = countPowersOfThreeBetween (low, high);
    printf ("In range %lu..%lu, found %u occurrences\n", low, high, count);
}

// Test suite, add whatever you need.

int main (void) {
    testRange (1000, 10);
    testRange (0, 0);
    testRange (9, 9);
    testRange (3, 1000);
    testRange (0, ULONG_MAX);
    testRange (ULONG_MAX, ULONG_MAX);
    return 0;
}

正如您将从输出中看到的,这为各种范围提供了正确的计数:

In range 1000..10, found 0 occurrences
In range 0..0, found 0 occurrences
In range 9..9, found 1 occurrences
In range 3..1000, found 6 occurrences
In range 0..18446744073709551615, found 41 occurrences
In range 18446744073709551615..18446744073709551615, found 0 occurrences

并且,如果您取消注释printf中的countPowersOfThreeBetween()行,您还会看到检测到的实际值。

答案 2 :(得分:0)

在将来选择浮点类型之前,我强烈建议您阅读this article entitled "What every computer scientist should know about floating-point arithmetic", by David Goldberg。它很好地解释了你的问题,比我想象的要好得多。

您实际上并不需要浮点(或负整数)类型,因此应避免使用它们。通过乘法形成你的能力,而不是加法:

/* ******************************************************************* */
// armaMex_demo2.cpp: Modified from armaMex_demo.cpp copyright Conrad Sanderson and George Yammine.
/* ******************************************************************* */
// Demonstration of how to connect Armadillo with Matlab mex functions.
// Version 0.2
// 
// Copyright (C) 2014 George Yammine
// Copyright (C) 2014 Conrad Sanderson
// 
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
/////////////////////////////
#include "armaMex.hpp"


void
mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  /* 
     Input:   X (real matrix)
     Output:  Eigenvalues of X X.T
  */


  if (nrhs != 1)
    mexErrMsgTxt("Incorrect number of input arguments.");


  // Check matrix is real
  if( (mxGetClassID(prhs[0]) != mxDOUBLE_CLASS) || mxIsComplex(prhs[0]))
    mexErrMsgTxt("Input must be double and not complex.");


  // Create matrix X from the first argument.
  arma::mat X = armaGetPr(prhs[0],true);


  // Run an arma function  (eig_sym)
  arma::vec eigvals(X.n_rows);
  if(not arma::eig_sym(eigvals, X*X.t()))
    mexErrMsgTxt("arma::eig_sym failed.");    


  // return result to matlab
  plhs[0] = armaCreateMxMatrix(eigvals.n_elem, 1);
  armaSetPr(plhs[0], eigvals);

  return;
}

答案 3 :(得分:0)

你的问题是在计算机中浮点计算时的舍入错误,log(243)/ log(3)的结果不完全是log3(243),其中计算机存储它的近似值。例如,在我的32位计算机中,它是4.99999999999999911182。

但是,您有两种方法可以解决它,

  1. 使用整数计算而不是浮点数。
  2. 简单的数学变换。 [start,end]中3的幂数相当于floor(log3(end)-log3(start))+ 1,写在c中是

    printf(&#34;回答:%d \ n&#34;,(int)((log(1000)-log(3))/ log(3))+ 1);

  3. 完整代码:

    #include <stdio.h>
    #include <math.h>
    
    int pow3(int n) {
        int ret = 1;
        while(n--) {
            ret *= 3;
        }
        return ret;
    }
    
    int main() {
        int a, start, end, answer;
        scanf("%d%d", &start, &end);
        a = (int)(log(start+0.5)/log(3));
        //printf("%d,%d,%d\n", a, pow3(a), start);
        if(start == end) answer = (start == pow3(a));
        else answer = (int)((log(end+0.5)-log(start))/log(3))+1;
        printf("answer = %d\n", answer);
    
    }
    

    结果:

    Input[0]: 2 10
    Output[0]: 2
    Input[1]: 1 3
    Output[1]: 2
    Input[2]: 3 1000
    Output[2]:6
    

答案 4 :(得分:0)

由于浮点精度问题,您的程序失败。

改为使用整数算术:

#include <limits.h>
#include <stdio.h>

int main(void) {
    unsigned int start, end, i, count;

    printf("Enter start and end: ");
    if (scanf("%u %u", &start, &end) == 2) {
        for (i = 1, count = 0; i <= end && i <= UINT_MAX / 3; i *= 3) {
            if (i >= start) {
                printf("%u\n", i);
                count++;
            }
        }
        printf("Answer = %u\n", count);
    }
    return 0;
}

使用浮点算术的直接解决方案也是可能的:

#include <math.h>
#include <stdio.h>

int main(void) {
    unsigned int start, end, count = 0;

    printf("Enter start and end: ");
    if (scanf("%u %u", &start, &end) == 2) {
        if (end > 0 && end >= start) {
            int start3 = (start <= 1) ? 0 : (int)(log(start - 0.5) / log(3));
            int end3 = (int)(log(end + 0.5) / log(3));
            count = end3 - start3;
        }
        printf("Answer = %u\n", count);
    }
    return 0;
}