【问题标题】:The most efficient way to reverse a number反转数字的最有效方法
【发布时间】:2013-03-12 06:52:36
【问题描述】:

我正在寻找一种有效的算法来反转一个数字,例如

输入: 3456789

输出: 9876543

在 C++ 中,有很多带有移位和位掩码的选项,但最有效的方法是什么?

我的平台:x86_64

数字范围:XXX - XXXXXXXXXX(3 - 9 位)

编辑 我输入的最后一位永远不会是零,因此不存在前导零问题。

【问题讨论】:

  • 如果您不将其视为数字,为什么不将其视为字符串?反转它是微不足道的。
  • @hvd 这会导致调用字符串构造函数、赋值运算符、析构函数......我不确定这是否是最有效的方法。
  • 您想要前导零吗?对于前导零的情况,提供的两个答案都失败。
  • 你真的需要“最高效的方式”吗?这真的是所有处理时间都花在程序中的地方吗?对我来说,这听起来像是过早的优化。
  • 移位和位掩码?不是以 10 为基数。如果你想在 16 基数中执行此操作,我会有一些不错的技巧,但二进制计算机就是不喜欢以 10 为基数。

标签: c++ performance algorithm optimization


【解决方案1】:

这样的事情会起作用:

#include <iostream>

int main()
{
    long in = 3456789;
    long out = 0;
    while(in)
    {
        out *= 10;
        out += in % 10;
        in /= 10;
    }
    std::cout << out << std::endl;
    return 0;
}

【讨论】:

  • @H2CO3 这个答案真的很常见。不是很难或令人印象深刻,无法复制。
  • @H2CO3 不,我是分开写的,其实
  • @H2CO3 - 嗯,我正在回复你的答案,但你似乎已经删除了你的答案。我只是暂时删除了我的赞成票,因为我意识到我应该研究 math.stackexchange.com,以防万一存在更有效的解决方案(例如一步公式)。但是那里的数学家没有想出任何这样的东西,只有a compact form你(和斯蒂芬林)写的算法。所以,在精神上恢复支持。
  • @acheong87 谢谢。我删除了我的答案,因为事实证明它是错误的,就像这个一样。它不计算尾随零,XYZ0 变为 ZYX 而不是 0ZYX
  • @H2CO3 我也不介意把它记下来,但不清楚 OP 想要什么,因为他提到了位移等(所以大概他想要一个数字而不是字符串表示)
【解决方案2】:
#include <stdio.h>
unsigned int reverse(unsigned int val)
{
 unsigned int retval = 0;

 while( val > 0)
 {
     retval  = 10*retval + val%10;
     val     /= 10;
 }
 printf("returning - %d", retval);
 return retval;
}


int main()
{
    reverse(123);
}

【讨论】:

    【解决方案3】:

    您可以将数字转换为字符串,然后使用 STL 算法反转字符串。下面的代码应该可以工作:

     long number = 123456789;
     stringstream ss;
     ss << number;
     string numberToStr = ss.str();
    
     std::reverse(numberToStr.begin(), numberToStr.end());
    
     cout << atol(numberToStr.c_str());
    

    您可能需要包含那些相关的头文件。我不确定这是否是最有效的方法,但 STL 算法通常非常有效。

    【讨论】:

      【解决方案4】:
      int ans=0;
      int rev(int n)
      {
        ans=(ans+(n%10))*10; // using recursive function to reverse a number;
        if(n>9) 
          rev(n/10);
      }
      
      int main()
      {
        int m=rev(456123); // m=32
        return 0;
      }
      

      【讨论】:

      • 这是最有效的方法吗?
      • 不考虑内存,但在解决问题时会派上用场:)
      【解决方案5】:
      static public int getReverseInt(int value) {
          int resultNumber = 0;
          for (int i = value; i != 0;) {
              int d = i / 10;
              resultNumber = (resultNumber - d) * 10 + i;
              i = d;
          }
          return resultNumber;
      }
      

      我认为这将是不使用asm 的最快方法。请注意,d*10 + i 等价于 i%10,但速度要快得多,因为模数比乘法慢 10 倍左右。
      我对其进行了测试,它比其他答案快 25%。

      【讨论】:

        【解决方案6】:
         //Recursive method to find the reverse of a number  
         #include <bits/stdc++.h> 
            using namespace std; 
            int reversDigits(int num) 
            { 
            static int rev_num = 0; 
            static int base_pos = 1; 
            if(num > 0) 
            { 
                reversDigits(num/10); 
                rev_num += (num%10)*base_pos; 
                base_pos *= 10; 
            } 
            return rev_num; 
            } 
            int main() 
            { 
                int num = 4562; 
                cout << "Reverse  " << reversDigits(num); 
            } ``
        

        【讨论】:

          【解决方案7】:
          // recursive method to reverse number. lang = java
          static void reverseNumber(int number){
              // number == 0 is the base case
              if(number !=0 ){
                  //recursive case
                  System.out.print(number %10);
                  reverseNumber(number /10);
              }
          }
          

          【讨论】:

            【解决方案8】:

            此解决方案效率不高,但确实解决了问题并且很有用。 它为任何有符号整数(int、long、long long 等)返回 long long,为任何无符号整数(unsigned int、unsigned long、unsigned long long 等)返回 unsigned long long。

            char 类型取决于编译器实现,可以有符号或无符号。

            #include <iostream>
            #include <string>
            #include <algorithm>
            
            
            template <bool B>
            struct SignedNumber
            {
            };
            
            template <>
            struct SignedNumber<true>
            {
                typedef long long type;
            };
            
            template <>
            struct SignedNumber<false>
            {
                typedef unsigned long long type;
            };
            
            template <typename TNumber = int,
                      typename TResult = typename SignedNumber<std::is_signed<TNumber>::value>::type,
                      typename = typename std::void_t<std::enable_if_t<std::numeric_limits<TNumber>::is_integer>>>
            TResult ReverseNumber(TNumber value)
            {
                bool isSigned = std::is_signed_v<TNumber>;
                int sign = 1;
                if (value < 0)
                {
                    value *= -1;
                    sign = -1;
                }
                std::string str = std::to_string(value);
                std::reverse(str.begin(), str.end());
                return isSigned ? std::stoll(str) * sign : std::stoull(str) * sign;
            }
            
            int main()
            {
                std::cout << ReverseNumber(true) << std::endl; //bool -> unsigned long long
                std::cout << ReverseNumber(false) << std::endl; //bool -> unsigned long long
                std::cout << ReverseNumber('@') << std::endl; //char -> long long or unsigned long long 
                std::cout << ReverseNumber(46) << std::endl; //int -> long long
                std::cout << ReverseNumber(-46) << std::endl; //int -> long long
                std::cout << ReverseNumber(46U) << std::endl; //unsigned int -> unsigned long long
                std::cout << ReverseNumber(46L) << std::endl; //long -> long long
                std::cout << ReverseNumber(-46LL) << std::endl; //long long -> long long
                std::cout << ReverseNumber(46UL) << std::endl; //unsigned long -> unsigned long long
                std::cout << ReverseNumber(4600ULL) << std::endl; //unsigned long long -> unsigned long long
            }
            

            输出

            1
            0
            64
            64
            -64
            64
            64
            -64
            64
            64
            

            测试这段代码
            https://repl.it/@JomaCorpFX/IntegerToStr#main.cpp

            【讨论】:

              【解决方案9】:

              如果它是 32 位无符号整数(最大输入为 987,654,321)并且如果您有 4GB 可用内存(按效率,您是指内存吗?),

              result=table[value]; // index 12345 has 54321, index 123 has 321
              

              应该足够快。假设以 100 ns 时间或 200 个周期访问内存,整数平均为 7 位,其他解决方案有:

              • 7 次乘法,
              • 7 添加,
              • 7 模,
              • 7 个师,
              • 7 次循环迭代,7 次比较

              如果这些时间超过 100 纳秒/200 个周期,那么 table 会更快。例如,1 个整数除法可以高达 40 个周期,所以我想这可能足够快。如果输入是重复的,那么来自缓存的数据将具有更少的延迟。

              但是,如果有数百万个并行的反向操作,那么 CPU 计算绝对是比访问表更好的选择(使用矢量化计算循环 + 多线程可能会加速 30 到 100 倍)。它每个核心和多个核心有多个管道。您甚至可以选择带有 GPU 的 CUDA/OpenCL 以获得额外的吞吐量,并且这种与其他答案相反的解决方案看起来非常令人尴尬地可并行化,因为 1 个输入独立于其他输入进行计算。

              【讨论】:

                【解决方案10】:

                这是最简单的一个:

                #include<iostream>
                using namespace std;
                
                int main()
                {
                int number, reversed=0;
                cout<<"Input a number to Reverse: ";
                cin>>number;
                    while(number!=0)
                  {
                    reversed= reversed*10;
                    reversed=reversed+number%10;
                    number=number/10;
                  }
                cout<<"Reversed number is: "<<reversed<<endl;
                
                }
                

                【讨论】:

                  猜你喜欢
                  • 2011-10-09
                  • 2011-06-15
                  • 2011-07-13
                  • 2010-11-17
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-01-21
                  • 1970-01-01
                  • 2020-10-24
                  相关资源
                  最近更新 更多