C++打印整数、浮点数的二进制
Tuesday, February 28, 2023
本文共1174字
3分钟阅读时长
⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/posts/c++%E6%89%93%E5%8D%B0%E6%95%B4%E6%95%B0%E6%B5%AE%E7%82%B9%E6%95%B0%E7%9A%84%E4%BA%8C%E8%BF%9B%E5%88%B6/。商业转载请联系作者获得授权,非商业转载请注明出处!
You give before you get.
— Napoleon Hill
打印整数
打印整数很简单,只需要位运算就好了。
我使用了模板,这样就能针对不同长度的整数类型只用写一次代码:
template<typename T>
void _inner_print_bin(T num, char length){
bool still_head = true;
for (char i = length; i >= 0; i--)
{
char tmp = (num >> i) & 0x1;
if ((still_head && tmp) || !still_head)
{
std::cout << (short)tmp ;
still_head = false;
}
}
std::cout << '\n';
}
template<typename T>
void printnum(T num){
std::ios::sync_with_stdio(false);
_inner_print_bin(num, sizeof(T)*8-1);
}
浮点数二进制打印
浮点数因为IEEE754的规定比较麻烦。
整个浮点数分为sign(符号位)、exponent(指数)、mantissa(尾数)三部分组成
具体来说,最后小数的真实值 = $(-1)^{sign}*2^{exponent}*mantissa$,知道这个,我们只需要使用掩码就能分别得到sign、exponent和mantissa,然后进行一定的运算就能得到小数的二进制表示:
inline uint64_t mask_double_mantissa(uint64_t bits){
return (bits & 0xFFFFFFFFFFFFF) | ((uint64_t)0x1 << 52);
};
inline int64_t mask_double_exponent(uint64_t bits){
return ((int64_t)((bits >> 52) & 0x7FF)) - 1023;
}
inline char mask_double_sign(uint64_t bits){
return (bits >> 63) & 1;
}
inline uint32_t mask_float_mantissa(uint32_t bits){
return (bits & 0x7FFFFF) | (0x1 << 23);
};
inline int32_t mask_float_exponent(uint32_t bits){
return ((int32_t)((bits >> 23) & 0xFF)) - 127;
}
inline char mask_float_sign(uint32_t bits){
return (bits >> 31) & 1;
}
template<typename T1, typename T2>
void _inner_print_bin(T1 num, T2 exp, char length){
bool still_head = true;
char cnt = 0;
for (char i = length; i >= 0; i--)
{
char tmp = (num >> i) & 0x1;
if ((still_head && tmp) || !still_head)
{
std::cout << (short)tmp ;
still_head = false;
if (cnt == exp) std::cout << '.';
++cnt;
}
}
std::cout << '\n';
}
void printnum(double num){
std::ios::sync_with_stdio(false);
uint64_t bits = *(uint64_t*)#
char sign = mask_double_sign(bits);
int64_t exp = mask_double_exponent(bits);
uint64_t mantissa = mask_double_mantissa(bits);
if (sign == 1){
std::cout << '-';
}
if (exp > 0){
_inner_print_bin(mantissa, exp, 63);
}else{
std::cout << "0.";
for (unsigned char i = 0; i < (-exp) - 1; i++)
{
std::cout << '0';
}
_inner_print_bin(mantissa, 63);
}
}
void printnum(float num){
std::ios::sync_with_stdio(false);
uint32_t bits = *(uint32_t*)#
char sign = mask_float_sign(bits);
int32_t exp = mask_float_exponent(bits);
uint32_t mantissa = mask_float_mantissa(bits);
if (sign == 1){
std::cout << '-';
}
if (exp > 0){
_inner_print_bin(mantissa, exp, 31);
}else{
std::cout << "0.";
for (unsigned char i = 0; i < (-exp) - 1; i++)
{
std::cout << '0';
}
_inner_print_bin(mantissa, 31);
}
}
注意,浮点数规定第一位必须是符号位,所以不能用unsigned修饰
虽然有些编译器会自动转换类型,有些编译器会抛出warning使得编译可以通过,但是这种写法是需要避免的
完整代码:
printnum.h:
/*
* @Author : PeterLiu-all peterliuforever@gmail.com
* @Date : 2023-02-28T16:45:56+0800
* @LastEditTime : 2023-02-28T22:50:28+0800
* @LastEditors : PeterLiu-all peterliuforever@gmail.com
* @FilePath : \print_num\libprintnum\printnum.h
* @Description : libprintnum头文件
*/
#ifndef __LIBPRINTNUM_PRINTNUM_H__
#define __LIBPRINTNUM_PRINTNUM_H__
#include <stdint.h>
#include <iostream>
constexpr uint64_t mask_double_mantissa(uint64_t bits){
return (bits & 0xFFFFFFFFFFFFF) | ((uint64_t)0x1 << 52);
};
constexpr int64_t mask_double_exponent(uint64_t bits){
return ((int64_t)((bits >> 52) & 0x7FF)) - 1023;
}
constexpr char mask_double_sign(uint64_t bits){
return (bits >> 63) & 1;
}
constexpr uint32_t mask_float_mantissa(uint32_t bits){
return (bits & 0x7FFFFF) | (0x1 << 23);
};
constexpr int32_t mask_float_exponent(uint32_t bits){
return ((int32_t)((bits >> 23) & 0xFF)) - 127;
}
constexpr char mask_float_sign(uint32_t bits){
return (bits >> 31) & 1;
}
template<typename T>
void _inner_print_bin(T num, char length){
bool still_head = true;
for (char i = length; i >= 0; i--)
{
char tmp = (num >> i) & 0x1;
if ((still_head && tmp) || !still_head)
{
std::cout << (short)tmp ;
still_head = false;
}
}
std::cout << '\n';
}
template<typename T1, typename T2>
void _inner_print_bin(T1 num, T2 exp, char length){
bool still_head = true;
char cnt = 0;
for (char i = length; i >= 0; i--)
{
char tmp = (num >> i) & 0x1;
if ((still_head && tmp) || !still_head)
{
std::cout << (short)tmp ;
still_head = false;
if (cnt == exp) std::cout << '.';
++cnt;
}
}
std::cout << '\n';
}
template<typename T>
void printnum(T num){
std::ios::sync_with_stdio(false);
_inner_print_bin(num, sizeof(T)*8-1);
}
// 注意,浮点数规定第一位必须是符号位,所以不能用unsigned修饰
// 虽然有些编译器会自动转换类型,有些编译器会抛出warning使得编译可以通过,但是这种写法是需要避免的
void printnum(double num);
void printnum(float num);
#endif /* __LIBPRINTNUM_PRINTNUM_H__ */
printnum.c:
/*
* @Author : PeterLiu-all peterliuforever@gmail.com
* @Date : 2023-02-28T16:45:48+0800
* @LastEditTime : 2023-02-28T21:53:52+0800
* @LastEditors : PeterLiu-all peterliuforever@gmail.com
* @FilePath : \print_num\libprintnum\printnum.cpp
* @Description : 模板全特化
*/
#include "printnum.h"
void printnum(double num){
std::ios::sync_with_stdio(false);
uint64_t bits = *(uint64_t*)#
char sign = mask_double_sign(bits);
int64_t exp = mask_double_exponent(bits);
uint64_t mantissa = mask_double_mantissa(bits);
if (sign == 1){
std::cout << '-';
}
if (exp > 0){
_inner_print_bin(mantissa, exp, 63);
}else{
std::cout << "0.";
for (unsigned char i = 0; i < (-exp) - 1; i++)
{
std::cout << '0';
}
_inner_print_bin(mantissa, 63);
}
}
void printnum(float num){
std::ios::sync_with_stdio(false);
uint32_t bits = *(uint32_t*)#
char sign = mask_float_sign(bits);
int32_t exp = mask_float_exponent(bits);
uint32_t mantissa = mask_float_mantissa(bits);
if (sign == 1){
std::cout << '-';
}
if (exp > 0){
_inner_print_bin(mantissa, exp, 31);
}else{
std::cout << "0.";
for (unsigned char i = 0; i < (-exp) - 1; i++)
{
std::cout << '0';
}
_inner_print_bin(mantissa, 31);
}
}
扫码阅读此文章
点击按钮复制分享信息
点击订阅