【问题标题】:How to create a number with (f)16 repeating n times?如何创建一个 (f)16 重复 n 次的数字?
【发布时间】:2021-01-17 05:34:41
【问题描述】:

我需要创建一个数字,其中 (f)16 重复 n 次。 0

我尝试了以下例如 n = 16

std::cout << "hi:" << std::hex << std::showbase << (1ULL << 64) - 1 << std::endl;

警告:移位计数 >= 类型 [-Wshift-count-overflow] 的宽度 std::cout

嗨:0x200

如何在不溢出ULL 的情况下获取所有数字f

【问题讨论】:

  • 尝试使用4 的倍数作为您移动的幻数。
  • 陈述人们一直在暗示的内容:如果unsigned long long 有64 位,那么(1ULL &lt;&lt; 64) - 1 具有明确定义和可移植的行为,并将赋予价值0xffffffffffffffffULL
  • @aschepler: 1ULL &lt;&lt; 64 没有明确定义或可移植的行为。根据 C++ 草案 N4659 8.8 1,“如果右操作数为负数,或者大于或等于提升的左操作数的位长度,则行为未定义。”
  • @Someprogrammerdude:使用变量可能会规避警告,但不会规避未定义的行为。根据我对上述 C++ 标准的引用,无论移位量是否为常量,标准都没有定义与类型中的位数一样多的移位。
  • @puio:这种情况下的行为也没有由 C++ 标准定义,因为 &lt;&lt; n*4 移动了 64 位,但您的实现中 unsigned long long 的宽度是 64 位。

标签: c++ bit-manipulation 64-bit bitmask


【解决方案1】:

如果您只对十六进制格式和数字 f 感兴趣,请使用其他答案。

下面的函数可以生成十六进制和十进制格式以及任何数字的数字。

#include <iostream>

uint64_t getNum(uint64_t digit, uint64_t times, uint64_t base)
{
    if (base != 10 && base != 16) return 0;
    if (digit >= base) return 0;
    
    uint64_t res = 0;
    uint64_t multiply = 1;
    for(uint64_t i = 0; i < times; ++i)
    {
        res += digit * multiply;
        multiply *= base;
    }
    return res;
}

int main() {
    std::cout << getNum(3, 7, 10) << std::endl;
    std::cout << std::hex << getNum(0xa, 14, 16) << std::dec << std::endl;
    return 0;
}

输出:

3333333
aaaaaaaaaaaaaa

注意:当前代码没有溢出检测。

【讨论】:

    【解决方案2】:

    您可以编写一个单独的函数来查找例如以下方式。

    #include <stdio.h>
    
    unsigned long long create_hex( size_t n )
    {
        unsigned long long x = 0;
        
        n %= 2 * sizeof( unsigned long long );
    
        while ( n-- )
        {
            x = x << 4 | 0xf;
        }
        
        return x;
    }
    
    int main( void ) 
    {
        for ( size_t i = 0; i <= 16; i++ )
        {
            printf( "%zu -> %llx\n", i, create_hex( i ) );
        }
    }   
    

    程序输出是

    0 -> 0
    1 -> f
    2 -> ff
    3 -> fff
    4 -> ffff
    5 -> fffff
    6 -> ffffff
    7 -> fffffff
    8 -> ffffffff
    9 -> fffffffff
    10 -> ffffffffff
    11 -> fffffffffff
    12 -> ffffffffffff
    13 -> fffffffffffff
    14 -> ffffffffffffff
    15 -> fffffffffffffff
    16 -> 0
    

    最初您使用两种语言标记,C 和 C++,然后将这个程序作为 C++ 程序运行,将标题 &lt;stdio.h&gt; 替换为 &lt;iostream&gt;,并使用运算符 printf。

    【讨论】:

    • 问题的第一句清楚地表明 n = 16 被包括在内并且应该产生 ffffffffffffffff (以 16 为底),并且这个答案显示 n = 16 的输出为 0。这怎么可能是正确答案?
    • @EricPostpischil 我认为这是错误的情况。
    【解决方案3】:

    如果n 为16 位且unsigned long long 为64 位,则由于4*n 位的移位存在问题,因此您可以通过较小的移位量来解决该问题。如果已知n 是正数,我们可以将其划分为两个班次:

    (1ull << 4 << 4*(n-1)) - 1u
    

    而且,由于1ull &lt;&lt; 4 是一个常数,我们可以替换它:

    (0x10ull << 4*(n-1)) - 1u
    

    如果n 可以为零,那么,为了支持从 0 到 16 的任何值,我们不能使用单个表达式。一个解决方案是:

    n ? 0 : (0x10ull << 4*(n-1)) - 1u
    

    【讨论】:

    • 通过使用符号扩展移位,从 0 到 16 的任何值的大小写也可以由单个表达式处理,例如 uint64_t(int64_t(-n) &gt;&gt; 63) &gt;&gt; ((-n &lt;&lt; 2) &amp; 63)int64_t(n - 0x8000000000000010) &gt;&gt; (~(n &lt;&lt; 2) &amp; 63)
    【解决方案4】:

    对于 n = 1 到 16,您可以从所有 F 开始,然后相应地移动:

    0xFFFFFFFFFFFFFFFFULL >> (4*(16-n));
    

    (单独处理 n=0)

    【讨论】:

    • 这最符合我的需要!
    • 这只是翻转了您需要处理的特殊情况。真正的问题是n有65个可能的值,0到64(含),但是>只能处理64个可能的值。
    • @MSalters 到目前为止没有人问过它。感谢您的提问,n 不能为 0。其他答案很好。请为他们投票。提问者应该接受对他们最有帮助的东西。我在这和stackoverflow.com/a/64156781/14170429 之间纠结
    • 如果需要处理n=0,总有` (n==0)?0ULL : 0xFFFFFFFFFFFFFFFFULL >> (4*(16-n))`
    【解决方案5】:

    其中 (f)16 重复 n 次。

    如果我理解正确,我相信那是微不足道的。添加一个f。将数字左移 4 位。添加另一个f。左移 4 位。添加另一个f。重复n 次。

    #include <stdio.h>
    unsigned long long gen(unsigned n) {
         unsigned long long r = 0;
         while (n--) {
             r <<= 4;
             r |= 0xf;
         }
         return r;
    }
    int main() {
        for (int i = 0; i < 16; ++i) {
            printf("%d -> %llx\n", i, gen(i));
        }
    }
    

    输出:

    0 -> 0
    1 -> f
    2 -> ff
    3 -> fff
    4 -> ffff
    5 -> fffff
    6 -> ffffff
    7 -> fffffff
    8 -> ffffffff
    9 -> fffffffff
    10 -> ffffffffff
    11 -> fffffffffff
    12 -> ffffffffffff
    13 -> fffffffffffff
    14 -> ffffffffffffff
    15 -> fffffffffffffff
    

    【讨论】:

    • 是的,你没看错!谢谢。对于 C/C++ 的混淆,我们深表歉意。我不认为这两种语言的位操作会有很大的不同。我会接受最简洁的答案。
    猜你喜欢
    • 1970-01-01
    • 2019-07-22
    • 2021-11-30
    • 2011-11-13
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    相关资源
    最近更新 更多