鱼C论坛

 找回密码
 立即注册
楼主: BlackWhite_idea

[已解决]很纳闷这两种方式不是注释那段更简便?为什么不能输出

[复制链接]
发表于 2021-11-29 21:28:31 | 显示全部楼层
lightninng 发表于 2021-11-29 21:22
从结果看,不准的应该是pow吧,2的次方怎么可能是偶数呢,盲猜是因为二进制的问题~

而且我知道我的问题出现在哪里了,
2 << 0 = 2
pow(2, 0) = 1

问题出现在 i = 0 的时候,而且

2 << 2 = 8
pow(2, 2) = 4

位元必须 i-1 才正确
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 21:29:22 | 显示全部楼层
傻眼貓咪 发表于 2021-11-29 21:18
感谢指教,确实我的错了。

而且我又发现新知识了:位元运算为什么不比 pow() 准?

        double 精度比位元操作精度高?完全不可能!
        试试这个代码,纯粹的位元操作,看看精度如何?
#include <stdio.h>

int main(void)
{
        unsigned long long d , i                             ;
        for(d = i = 0 , d = 0 ; i < 64 ; i ++) d |= 1LL << i ;
        printf("%I64u\n" , d)                                ;
}
        编译、运行实况:
D:\00.Excise\C>g++ -o x x.c

D:\00.Excise\C>x
18446744073709551615

D:\00.Excise\C>
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 21:41:39 | 显示全部楼层
jackz007 发表于 2021-11-29 21:29
double 精度比位元操作精度高?完全不可能!
        试试这个代码,纯粹的位元操作,看看精度 ...

受教了,C/C++ 语言确实很多需要学。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-11-29 21:55:01 | 显示全部楼层
lightninng 发表于 2021-11-29 20:49
仔细观察

上面这段代码等价的代码应该是

就是这样用的话,C不输出。、、、
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 22:05:06 | 显示全部楼层
jackz007 发表于 2021-11-29 21:29
double 精度比位元操作精度高?完全不可能!
        试试这个代码,纯粹的位元操作,看看精度 ...

感谢你的代码,我悄悄简化了一下:
#include <stdio.h>
#include <math.h>

int main()
{
    unsigned long long wheat = (unsigned long long)(pow(2, 64) - 1);
    printf("舍罕王应该给予达依尔 %llu 粒麦子!!!", wheat);
    return 0;
}
输出:
舍罕王应该给予达依尔 18446744073709551615 粒麦子!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 22:08:32 | 显示全部楼层
傻眼貓咪 发表于 2021-11-29 22:05
感谢你的代码,我悄悄简化了一下:输出:

         这个想法很妙!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 22:10:20 | 显示全部楼层

多亏你了,我完全没有想到位元 OR 这点,然后我就结合数学知识得出这个
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 22:18:23 | 显示全部楼层
傻眼貓咪 发表于 2021-11-29 22:10
多亏你了,我完全没有想到位元 OR 这点,然后我就结合数学知识得出这个

        确实,只有老鸟才会想到这个办法,菜鸟们是万万想不到的,我也没有想到!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 22:21:57 | 显示全部楼层
jackz007 发表于 2021-11-29 22:18
确实,只有老鸟才会想到这个办法,菜鸟们是万万想不到的,我也没有想到!

共同学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 22:25:56 | 显示全部楼层

        互相学习!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 23:13:21 | 显示全部楼层
问题在于一个是进行整数运算,一个是浮点数运算
而浮点数运算是有精度损失的,进行运算的数越大,损失就越大

看下面的代码
#include <stdio.h>
#include <math.h>

int main(void) {
    int i;
    unsigned long long int mi = 0;
    unsigned long long int sum = 0;
    unsigned long long int x = 0;
    for(i = 0; i <= 64; i++) {
        mi = pow(2, i); sum += mi;
        x += pow(2,i);
        if(i == 51 || i == 52 || i == 53 || i == 54) {
            printf("%d: %llu\n", i, sum);
            printf("%d: %llu\n", i, x);
        }
    }
    printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", x);
    printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", sum);
    return 0;
}
$ ./main
51: 4503599627370495
51: 4503599627370495
52: 9007199254740991
52: 9007199254740991
53: 18014398509481983
53: 18014398509481984
54: 36028797018963967
54: 36028797018963968
舍罕王应该给予达依尔0粒麦子!!!
舍罕王应该给予达依尔18446744073709551615粒麦子!!!
$ 

当 i 等于 52 的时候还是正常的,但是到 i 等于 53 的时候就开始出现问题了
一个的结果是
18014398509481983
另一个是
18014398509481984


那最后为什么有一个输出的是 0 ?
看下面的代码

在看下面的代码之前,先看一下你的代码
        int i;
        unsigned long long int mi = 0;
        unsigned long long int sum = 0;
        for(i=0;i<=64;i++)
        {
                mi = pow(2,i);
                sum += mi;
                
//                mi += pow(2,i);
        }
//        printf("舍罕王应该给予达依尔%llu粒麦子!!!",mi);
        printf("舍罕王应该给予达依尔%llu粒麦子!!!",sum);

再看标准答案
#include <stdio.h>
#include <math.h>

int main()
{
        unsigned long long sum = 0;
        unsigned long long temp;
        unsigned long long weight;
        int i;

        for (i=0; i < 64; i++)
        {
                temp = pow(2, i);
                sum = sum + temp;
        }

        weight = sum / 25000;

        printf("舍罕王应该给予达依尔%llu粒麦子!\n", sum);
        printf("如果每25000粒麦子为1kg,那么应该给%llu公斤麦子!\n", weight);

        return 0;
}

看出哪里不一样了吗?
for (i=0; i < 64; i++)
for(i=0;i<=64;i++)

看出来了吗?

所以,代码改成这样
#include <stdio.h>
#include <math.h>

int main(void) {
    int i;
    unsigned long long int mi = 0;
    unsigned long long int sum = 0;
    unsigned long long int x = 0;
    //for(i = 0; i <= 64; i++) {
    for(i = 0; i < 64; i++) {
        mi = pow(2, i); sum += mi;
        x += pow(2,i);
        if(i == 62) {
            printf("%d: %llu\n", i, x);
            unsigned long long int temp = pow(2, 63);
            printf("temp: %llu\n", temp);
            x += temp;
            printf("x: %llu\n", x);
        }
    }
    printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", x);
    printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", sum);
    return 0;
}
$ ./main
62: 9223372036854775808
temp: 9223372036854775808
x: 0
舍罕王应该给予达依尔9223372036854775808粒麦子!!!
舍罕王应该给予达依尔18446744073709551615粒麦子!!!
$ 

在第 62 次的时候
x 的值是 9223372036854775808
temp 是 9223372036854775808

x + temp = 9223372036854775808 + 9223372036854775808
= 18446744073709551616
18446744073709551616 这个数字太大了,unsigned long long int 也放不下
这个数字十进制形式不太明显,换成十六进制形式
18446744073709551616 = 0x10000000000000000
对于 unsigned long long int,正好最前面的 1 放不下,后面全是 0,所以最后输出的是 0


那为什么 i 等于 64 的时候 sum 的值不是 0 ?看起来是个正确的值?
就是这个代码
for(i=0;i<=64;i++)
#include <stdio.h>
#include <math.h>

int main(void) {
    int i;
    unsigned long long int mi = 0;
    unsigned long long int sum = 0;
    for(i = 0; i <= 64; i++) {
        mi = pow(2, i); sum += mi;
        if(i == 62 || i == 63 || i == 64) {
            printf("%d: %llu\n", i, sum);
        }
    }
    printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", sum);
    return 0;
}
$ ./main
62: 9223372036854775807
63: 18446744073709551615
64: 18446744073709551615
舍罕王应该给予达依尔18446744073709551615粒麦子!!!
$ 

现在的问题变成了
为什么 i 等于 63 和 i 等于 64 的时候,sum 的值是一样的?
#include <stdio.h>
#include <math.h>

int main(void) {
    int i = 64;
    unsigned long long int x = pow(2, i);
    printf("%llu\n", x);
    return 0;
}
$ ./main
0
$ 

18446744073709551615 + 0 = 18446744073709551615
所以一样

为什么不把代码写成下面这样?
#include <stdio.h>
#include <math.h>

int main(void) {
    unsigned long long int x = pow(2, 64);
    printf("%llu\n", x);
    return 0;
}
$ ./main
18446744073709551615

为什么输出这个?
这我就不知道了,我感觉是编译器认为数字太大超范围了,就给 x 设置了一个 x 能表示的最大的数
你需要知道的是 pow(2, 64),是编译器直接算出来的,不是调用 math.h 中的 pow 函数

好了,没了,^_^
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 23:17:57 | 显示全部楼层
我又检查了一遍,希望没有说错的地方
^_^
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-29 23:22:25 | 显示全部楼层
好像漏了一个代码
这个
#include <stdio.h>
#include <math.h>

int main(void) {
    int i;
    unsigned long long int mi = 0;
    unsigned long long int sum = 0;
    unsigned long long int x = 0;
    for(i = 0; i < 64; i++) {
        mi = pow(2, i); sum += mi;
        x += pow(2,i);
    }
    printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", x);
    printf("舍罕王应该给予达依尔%llu粒麦子!!!\n", sum);
    return 0;
}
$ ./main
舍罕王应该给予达依尔0粒麦子!!!
舍罕王应该给予达依尔18446744073709551615粒麦子!!!

小于 64,输出也依然是 0

评分

参与人数 1鱼币 +3 收起 理由
BlackWhite_idea + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-30 00:43:18 | 显示全部楼层
本帖最后由 傻眼貓咪 于 2021-11-30 00:46 编辑

感谢大佬们指教,收益良多,这题解法大致三种:
#include <stdio.h>
#include <math.h>

int main()
{
    /*方法 1:位元 AND 运算符*/
    unsigned long long A = 1LL;
    for(unsigned long long i = 0; i < 64; i++) A ^= 2LL<<i;
    printf("A: %llu\n", A);
    
    /*方法 2:位元 OR 运算符*/
    unsigned long long B = 0;
    for(unsigned long long i = 0; i < 64; i++) B |= 1LL<<i;
    printf("B: %llu\n", B);
    
    /*方法 3:二次方运算*/
    unsigned long long C = (unsigned long long)(pow(2, 64)-1);
    printf("C: %llu", C);

    return 0;
}
输出:
A: 18446744073709551615
B: 18446744073709551615
C: 18446744073709551615
*注:以上三种都正确,只要明白其中原理,其实题目很简单就能解决,还是要感谢 22 楼大佬代码,让我突然清晰脑袋(有时做太多习题,往往会忘记基本)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-30 00:51:45 | 显示全部楼层
人造人 发表于 2021-11-29 23:22
好像漏了一个代码
这个

至於为什么 pow(2, 64)-1 会输出答案:如图(这是数学公式)

数学公式

数学公式
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-30 00:53:58 | 显示全部楼层
傻眼貓咪 发表于 2021-11-30 00:51
至於为什么 pow(2, 64)-1 会输出答案:如图(这是数学公式)

没明白你的这个回复
我最后的问题是
这个代码
#include <stdio.h>
#include <math.h>

int main(void) {
    unsigned long long int x = pow(2, 64);
    printf("%llu\n", x);
    return 0;
}

为什么输出这个?
$ ./main
18446744073709551615
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-30 00:58:23 | 显示全部楼层
傻眼貓咪 发表于 2021-11-30 00:43
感谢大佬们指教,收益良多,这题解法大致三种:输出:*注:以上三种都正确,只要明白其中原理,其实题目很 ...

我感觉你们讨论的问题不是题主问的问题

很纳闷这两种方式不是注释那段更简便?为什么不能输出


就像 lightninng 所言

难道人家问的不是为啥不能直接用mi+=pow(2,i);代替上面的语句?
其实上面大家指出的所有问题都没错,但是就是没有回答题主的问题~~~

我感觉要么是我和 lightninng 理解错题主的问题了,要么就是你们理解错了
我感觉我是对的
^_^
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-30 01:01:37 | 显示全部楼层
人造人 发表于 2021-11-30 00:53
没明白你的这个回复
我最后的问题是
这个代码

如图:表示 1+2+4+8 ......+9223372036854775808 = (2^64)-1

你想想看,假设...

i = 0, 二的0次方 = 1, sum = 1
i = 1, 二的1次方 = 2, sum = 3
i = 2, 二的2次方 = 4, sum = 7
i = 3, 二的3次方 = 8, sum = 15(你会发现每次 sum 就是 2 次方 -1)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-30 01:05:19 | 显示全部楼层
人造人 发表于 2021-11-30 00:58
我感觉你们讨论的问题不是题主问的问题

很纳闷这两种方式不是注释那段更简便?为什么不能输出

如果真的不明白我的解说,我也无能为力了,但是非常感谢这次楼主,让我学习很多
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-30 01:07:01 | 显示全部楼层
傻眼貓咪 发表于 2021-11-30 01:01
如图:表示 1+2+4+8 ......+9223372036854775808 = (2^64)-1

你想想看,假设...

不是,我没明白你说的这个是对我上面的哪个问题的补充或是指正
我上面提出了好多问题,除了最后一个,其他的问题都已自问自答的形式解决了
你的这个回复是指的我的哪一个问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-23 05:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表