首页 > 其他分享 >进制转换,base可能为负数

进制转换,base可能为负数

时间:2023-04-06 17:26:37浏览次数:38  
标签:进制 int 负数 base 余数 string

0x01 特殊:base=-2

LeetCode

0x02 前置知识:c++ %规则

我们需要知道,在 \(C\)++ 中,余数的符号取决于被除数,也即,a%b=c 中 \(c\) 的符号取决于 \(a\) 的符号,即,\(a\) 是什么符号,\(c\) 就是什么符号,与 \(b\) 的符号无关。

int a[4] = {11, 11, -11, -11};
int b[4] = {2, -2, 2, -2};
for(int i = 0; i < 4; i ++ )
    cout << a[i] / b[i] << "..." << a[i] % b[i] << endl;

输出结果为:

5...1
-5...1
-5...-1
5...-1

另外,a/b=c 中 \(c\) 的符号是显而易见的,如果 \(a\) 和 \(b\) 同符号,\(c\) 就是正号,反之,如果 \(a\) 和 \(b\) 异号,\(c\) 就是负号。
知道了上述规则,a/b=c..d 的 \(c\) 和 \(d\) 的值我们就可以自己求解了。

0x03 前置知识:取整规则

\(C\)++ 和 \(Java\) 是向 \(0\) 取整,\(Python\) 是下取整

0x04 十进制转其他进制 -- 辗转相除法

如果将一个 \(10\) 进制转换为一个 \(2,3,4,....n\)(正数) 进制,是很容易的,我们直接辗转相处然后对字符串 \(reverse\) 就行了。当然,如果数字不够用,还需要用到 \(a,b,c..\)
但是今天做到 0x01 这道题时,着实让我烧脑筋了,因为我想知道一种通用的解法,不仅仅局限于进制为 \(-2\) 的情况,对于 \(-3,-4,-5\) 甚至于 \(2,3,4\) 都可以通用的解决。
其实,当进制为负数时主要有一个问题:那就是,辗转相除时,余数可能为负数,此时该怎么办呢?

首先,余数为负数说明被除数肯定是个负数(\(0x02\))。
并且被除数(也就是 \(base\))也肯定是个负数,因为我们规定输入的十进制数都是正数,而这里被除数(十进制数)成了负数,说明此时除数肯定是负数。

好了,现在回归正题,我们肯定不能让余数为负数啊,所以我们需要把它转换为非负数。
直接告诉你方法:如果余数为负数,就加上进制的绝对值。
为什么这么做是正确的?因为我们可以很自然的修改商。
例如:十进制数为 \(a=-11\),进制为 \(b=-2\),商为 \(c\),余数为 \(d\)。
-11/-2=5...-1,因此我们需要让 \(d=-1+abs(-2)=1\),但是修改了 \(-1\),\(c*b+d==a\) 的等价关系就不成立了。
因此,我们还需要修改商,这里,我们只需要让商直接 \(+1\) 就好了。
因为让余数加上进制的绝对值就相当于让余数减去进制(前面证明了,进制一定是负数),所以我们需要让商 \(+1\),相当于把减去的进制加上了。
这样:(c+1)*b+(d-b)==c*b+d==a 依然成立。

如果我们不是让余数加上进制的绝对值,而是加上了一个其他的数,此时我们仍然需要通过改动商来维护等价关系(不可能修改进制,修改除数没意义)。
但是此时,商可能变成一个浮点数,例如,余数加上了 \(k\),那么我们需要让 (c+q)*b+(d+k)==c*b+d 成立。
就需要让 \(q=-k/b\),\(q\) 未必是个整数。

0x05 通解:abs(bsae)<10

当 \(base>=10\) 时需要用到 \(a,b,c,....\),这应该不会考到,也不需要用,\(16\) 进制就很好了。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cassert>
#include <cmath>

using namespace std;

const int N = 1024 * 1024;

// 将正整数n转换为base进制并输出结果
// abs(base) < 10 && base != 0
string toBaseStr(int n, int base);

// 测试程序
void test();
string toBaseStr(int n, int base);

int main()
{
    test();
    return 0;
}

string toBaseStr(int n, int base) 
{
    assert(base);
    if(n == 0)  return "0";
    string res("");
    while(n) 
    {
        int c = n % base;
        n /= base;
        if(c < 0) c -= base, n ++ ;
        res += to_string(c);
    }
    reverse(res.begin(), res.end());
    return res;
}

static void doTestBase(int base)
{
    int debuger = 0;
    for(int i = 0; i < N; i ++ )
    {
        string s = toBaseStr(i, base);
        string t = s;
        int n = s.size();
        int test = 0;
        
        reverse(t.begin(), t.end());
        for(int j = 0; j < n; j ++ )
            if(t[j] != '0') 
                test += (t[j] - '0') * pow(base, j);
        
        if(test != i)
            cout << "[Wrong" << ++ debuger << "]: " << i << "->" << s << " is " << test << endl;
        // else 
        //     cout << "[Accpet]: " << i << "->" << s << " is " << test << endl;
    }
    if(!debuger)
        cout << "[Accept] base = " << base << endl;
}

void test()
{
    clock_t start = clock();
    for(int i = 2; i < 10; i ++ )
    {
        doTestBase(i);
        doTestBase(-i);
    }
    printf("CPU Time = %.2lfs\n", (clock() - start) * 1.0 / CLOCKS_PER_SEC);
}

0x06 参考

ref here

标签:进制,int,负数,base,余数,string
From: https://www.cnblogs.com/ALaterStart/p/17293432.html

相关文章

  • 计算机2进制位运算
    按位与(&)0101&1001=0001//有一个为0则结果为0按位或(|)0101|1001=1101//有一个为1则结果为1按位取反(~)~0101=1010//0变1,1变0按位异或(^)0101^1001=1100//对应bit位相同,则结果位取0,否则取10异或任何数=任何数1异或任何数=任何数取反任何数异或自己=把自己置为0按位异或常见......
  • 二进制如何转十进制,十进制如何转二进制
    10进制转2进制就是除2取余数,按余数先后顺序排列:例如:5=5%2+2%2=101  2进制转10进制,从0位开始各位从低位开始乘以2的位次方结果相加:例如:110=0×2的0次方+1乘以2的1次方+1乘以2的2次方=6 听语音原创|浏览:9953631234567分步阅读学计算机的朋友刚开始学习时都要接触进制之间的转......
  • 颜色透明度16进制对照表
    https://www.colorhexa.com/color-nameshttps://htmlcolors.com/ 颜色透明度16进制对照表穷格万物关注42018.01.0211:18:38字数203阅读121,412100%—FF99%—FC98%—FA97%—F796%—F595%—F294%—F093%—ED92%—EB91%—E890%—E689%—E388%—E087%......
  • neondatabase 开源的k8s postgres autoscaling 工具
    autoscalingneondatabase开源的pg扩展工具(核心是解决neondatabase的一些问题),但是设计上有不少值得学习参考的地方参考架构  说明autoscaling设计上实现了自己的一个vm(支持在线迁移业务影响小),实现了自己的scheduler,也算是一个不错的k8s扩展开发参考项目参考资料......
  • Java进制转换
    publicstaticvoidmain(String[]args){ Scannerscan=newScanner(System.in); Stringrs="2022"; System.out.println(Integer.parseInt(rs,9)); scan.close();}上述代码实现的功能:将2022的9进制数转化为10进制......
  • 计算机中的编码和字符集:理解二进制、字节流和常见编码方案
    编码:将字符串转换到字节串的过程。解码:将字节串转换成字符串的过程。GB2312既是一种中文字符集,也是以ANSI标准为基础,实现的中文编码方案。它主要用于简体中文编码,是中国国家标准,于1981年发布。GBK是GB2312的超集。Unicode是一种字符集,定义了所有字符的唯一标识符(码点),同时......
  • Springboot 系列 (29) - Springboot+HBase 大数据存储(七)| Springboot 项目通过 Phoeni
    Phoenix是HBase的开源SQL皮肤,通过Phoenix可以使用标准JDBCAPI代替HBase客户端API来创建表,插入数据和查询HBase数据。Phoenix会把SQL编译成一系列的Hbase的scan操作,然后把scan结果生成标准的JDBC结果集,其底层由于使用了Hbase的API,协处理器,过滤器。Pho......
  • git merge 和 git rebase 的区别
    Git版本控制中,gitrebase和gitmerge这两个命令都可以用来集成从一个分支和另一个分支的更改。它们是两种不同的合并方法,本文将介绍它们的差异。gitrebase和gitmerge主要差异是什么?最近ChatGPT大火,请它来回答一下:Gitmerge将两个分支中的所有提交都合并到一起,并创建一......
  • 汉诺塔与二进制、满二叉树的千丝万缕
    汉诺塔(TowerofHanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子,其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。汉诺塔递归算法3......
  • 查看hbase表没有,但是新建却显示存在这个表的问题解决方案
    转:https://blog.csdn.net/leng91060404/article/details/106956315zookeeper数据存储及查看hbase信息1.zookeeper数据存储:1.1内存数据存储、磁盘数据存储.    内存数据存储:    数据模型是一棵树。包括所有节点路径,节点信息,ACL等。    DataTree:所有节点信息  ......