pow()函数在括号中使用时具有奇怪的行为并且具有长整数

时间:2016-05-02 22:30:03

标签: c brackets pow

我发现了一些奇怪的东西。

此函数将数字放在给定点的数字中,并返回修改后的数字。 现在我们想做put_digit(123456789123456784,0,9); 这将在数​​字的末尾加上9,替换最后一个数字(4)。

这是WORKS的代码:

long long int put_digit(long long int number, char place, char digit)
{
    long long int result = number;
    long long int power = number;

    power = pow(10, (place));
    result -= get_digit(number, place)*power;
    result += digit*pow(10, (place));

    return result;
}

代码返回123456789123456789

这是不起作用的代码:

long long int put_digit(long long int number, char place, char digit)
{
    long long int result = number;

    result -= get_digit(number, place)*pow(10, (place));
    result += digit*pow(10, (place));

    return result;
}

此代码返回123456789123456800作为结果。

函数get_digit()返回给定位置的数字。 这是代码:

char get_digit(long long int number, char place)
{
    long long int target = number;
    char digit = 0;

    target /= pow(10, place);
    digit = target % 10;

    return digit;
}

•低数字不会发生这种情况。

•get_digit()始终返回正确的值(在本例中为4)。

•get_digit()是一个char,因为它不是一个计数器函数,因此最好专注于使用更少的内存而不是使用像int这样的更快的变量。

•我尝试使用括号来避免麻烦的运算符优先级,但无济于事。

•执行put_digit(123456789123456000,2,7)时也会出现奇怪的行为,由于某种原因返回123456789123456704.这可以通过将第二个结果计算中的pow函数替换为变量“power”来解决。

我只是不明白为什么会这样。

我得到某种溢出吗?这是我的系统故障还是我自己的?我是否以糟糕的方式使用pow()?

1 个答案:

答案 0 :(得分:4)

pow()的声明是:double pow( double base, double exponent );

在第一种情况下:

long long int power = number;

power = pow(10, (place));

pow()返回的值在分配long long int时会转换为power。其余的计算使用整数进行处理,结果就是您期望的结果。

关于第二种情况:

result -= get_digit(number, place)*pow(10, (place));

get_digit(number, place)返回的值转换为double,因为它需要乘以浮点数(由pow()返回)。此外,在减去乘法结果之前,result的值将转换为double。最后,计算出的值从double转换为long long int,以存储在result中。

但从一定幅度开始,浮点数会失去最低有效数字的精度。

尝试使用这段简单的代码自己查看:

long long int i = 123456789123456785;

for (; i <= 123456789123456795; i ++) {
  printf("long long int: %lld; double: %f\n", i, (double)i);
}

输出:

long long int: 123456789123456785; double: 123456789123456784.000000
long long int: 123456789123456786; double: 123456789123456784.000000
long long int: 123456789123456787; double: 123456789123456784.000000
long long int: 123456789123456788; double: 123456789123456784.000000
long long int: 123456789123456789; double: 123456789123456784.000000
long long int: 123456789123456790; double: 123456789123456784.000000
long long int: 123456789123456791; double: 123456789123456784.000000
long long int: 123456789123456792; double: 123456789123456800.000000
long long int: 123456789123456793; double: 123456789123456800.000000
long long int: 123456789123456794; double: 123456789123456800.000000
long long int: 123456789123456795; double: 123456789123456800.000000

此行为不是错误,而是浮点数的限制。

代码的解决方案是在pow(10, place)返回后立即将long long int返回的值转换为result -= get_digit(number, place)*(long long int)pow(10, place);

animation: {
  duration: 0,
  onComplete: function () {
    var self = this,
        chartInstance = this.chart,
        ctx = chartInstance.ctx;

    ctx.font = '18px Arial';
    ctx.textAlign = "center";
    ctx.fillStyle = "#ffffff";

    Chart.helpers.each(self.data.datasets.forEach(function (dataset, datasetIndex) {
        var meta = self.getDatasetMeta(datasetIndex),
            total = 0, //total values to compute fraction
            labelxy = [],
            offset = Math.PI / 2, //start sector from top
            radius,
            centerx,
            centery, 
            lastend = 0; //prev arc's end line: starting with 0

        for (var val of dataset.data) { total += val; } 

        Chart.helpers.each(meta.data.forEach( function (element, index) {
            radius = 0.9 * element._model.outerRadius - element._model.innerRadius;
            centerx = element._model.x;
            centery = element._model.y;
            var thispart = dataset.data[index],
                arcsector = Math.PI * (2 * thispart / total);
            if (element.hasValue() && dataset.data[index] > 0) {
              labelxy.push(lastend + arcsector / 2 + Math.PI + offset);
            }
            else {
              labelxy.push(-1);
            }
            lastend += arcsector;
        }), self)

        var lradius = radius * 3 / 4;
        for (var idx in labelxy) {
          if (labelxy[idx] === -1) continue;
          var langle = labelxy[idx],
              dx = centerx + lradius * Math.cos(langle),
              dy = centery + lradius * Math.sin(langle),
              val = Math.round(dataset.data[idx] / total * 100);
          ctx.fillText(val + '%', dx, dy);
        }

    }), self);
  }
},