用 C 语言实现求补码的运算

news2025/6/22 19:00:50

缘起

前两天程序中需要求一堆参数的补码,一时犯懒,想从CSDN上搜一个勉强能用的代码借鉴一下,结果几乎没有搜到一个靠谱的!这种求补码的操作,用脚趾头想想也应该知道要用C或者C++的位运算来实现呀。结果搜到的一些实现方式竟然是把数值的二进制形式下的位,一位一位地进行操作!这简直离谱到家了,虽然这样做也能从功能上实现求补码的运算,但是性能肯定奇差呀。我们之所以用 C 或者 C++,通常都是对性能有一定的追求,如果你丝毫不在意性能,那你干嘛不去用 C# 或者 Java?

所以还是自己写了几个求补码的函数,分享在这里。本来觉得这是简单得不值一提的东西,但是看来并非人人都能把这件事情做对了。

之所以用 C 实现,而不是用 C++,是因为:(1) C 的函数可以在 C++ 中被无缝调用,反之则不行;(2) 用 C 实现,可以照顾到某些只能用 C 不能用 C++ 的嵌入式环境;(3) 这个实现过程实在是没有必要用到 C++ 的那些面向对象的特性,直接用 C 的过程式编程就足够了。我看到 CSDN 上有一个人实现求补码的过程,居然用到了 C++ 的 vector 容器,而且还对这个容器进行了动态地 insert 的操作,有这个必要吗??

从实际需求出发,我依次实现了对 8 位带符号整数、16 位带符号整数和 32 位带符号整数求补码的函数,以及它们的逆运算的函数。通常我们求补码的时候也不会希望求一个任意二进制字节流的补码,都是对实际的 8 位带符号整数、16 位带符号整数和 32 位带符号整数求补码进行求补码运算的。

原码、反码和补码的基础知识我就不在这里啰嗦了,CSDN 网站上介绍这些知识的文章多得是!我就直接上代码了。

程序实现

统一数据类型

对于 8 位整数、16 位整数和 32 位整数,为了照顾到不同的编译环境,我定义了一堆统一的数据类型,包括:

  1. 8位带符号和无符号整型:int8_t 与 uint8_t;
  2. 16位带符号和无符号整型:int16_t 与 uint16_t;
  3. 32位带符号和无符号整型:int32_t 与 uint32_t;

这些定义我放在了 datatypes.h 这个头文件里,通常我的 C / C++ 程序都会引用这个头文件:

#ifndef _INC_COMMON_datatypes_H
#define _INC_COMMON_datatypes_H

#if _MSC_VER && _MSC_VER < 1700
typedef __int8              int8_t;
typedef __int16             int16_t;
typedef __int32             int32_t;
typedef __int64             int64_t;
typedef unsigned __int8     uint8_t;
typedef unsigned __int16    uint16_t;
typedef unsigned __int32    uint32_t;
typedef unsigned __int64    uint64_t;
#else
#include <stdint.h>
#endif

typedef float           float32_t;
typedef double          float64_t;
typedef unsigned char	byte;
typedef char            sbyte;


#ifdef _WIN64
#define ssize_t __int64
#else
#define ssize_t long
#endif

#endif // !_INC_COMMON_datatypes_H

求补码的函数

头文件里面的函数原型定义:

#include "datatypes.h"

#ifdef __cplusplus
extern "C" {
#endif

    // 求 srcvalue 的8位补码, srcvalue 的取值范围是: [-128(-0x80), +127(+0x7F)]
    uint8_t I8_to_Complement(int8_t srcvalue);

    // 求 srcvalue 的16位补码, srcvalue 的取值范围是 : [-32768(-0x8000), +32767(+0x7FFF)]
    uint16_t I16_to_Complement(int16_t srcvalue);

    // 求 srcvalue 的32位补码, srcvalue 的取值范围是 : [-2147483648(-0x80000000), +2147483647(+0x7FFFFFFF)]
    uint32_t I32_to_Complement(int32_t srcvalue);

#ifdef __cplusplus
} // ! extern "C"
#endif

函数实现:

// 求 srcvalue 的8位补码, srcvalue 的取值范围是: [-128(-0x80), +127(+0x7F)]
uint8_t I8_to_Complement(int8_t srcvalue)
{
    uint8_t compcode;

    if (srcvalue >= 0)
    {
        compcode = (uint8_t)srcvalue;
        goto EXIT;
    }

    uint8_t tail = (uint8_t)(0 - srcvalue);
    tail = ~tail;
    compcode = tail + 1;

EXIT:
    return compcode;
}

// 求 srcvalue 的16位补码, srcvalue 的取值范围是 : [-32768(-0x8000), +32767(+0x7FFF)]
uint16_t I16_to_Complement(int16_t srcvalue)
{
    uint16_t compcode;

    if (srcvalue >= 0)
    {
        compcode = (uint16_t)srcvalue;
        goto EXIT;
    }

    uint16_t tail = (uint16_t)(0 - srcvalue);
    tail = ~tail;
    compcode = tail + 1;

EXIT:
    return compcode;
}

// 求 srcvalue 的32位补码, srcvalue 的取值范围是 : [-2147483648(-0x80000000), +2147483647(+0x7FFFFFFF)]
uint32_t I32_to_Complement(int32_t srcvalue)
{
    uint32_t compcode;

    if (srcvalue >= 0)
    {
        compcode = (uint32_t)srcvalue;
        goto EXIT;
    }

    uint32_t tail = (uint32_t)(0 - srcvalue);
    tail = ~tail;
    compcode = tail + 1;

EXIT:
    return compcode;
}

根据补码求原值(即:求补码运算的逆运算)

头文件里面的函数原型定义:

#include "datatypes.h"

#ifdef __cplusplus
extern "C" {
#endif

    // 求8位补码 compcode 的原值
    int8_t Complement_to_I8(uint8_t compcode);

    // 求16位补码 compcode 的原值
    int16_t Complement_to_I16(uint16_t compcode);

    // 求32位补码 compcode 的原值
    int32_t Complement_to_I32(uint32_t compcode);

#ifdef __cplusplus
} // ! extern "C"
#endif

函数实现:

// 求8位补码 compcode 的原值
int8_t Complement_to_I8(uint8_t compcode)
{
    int8_t srcvalue;

    uint8_t head = compcode & 0x80;
    if (head == 0)
    {
        srcvalue = (int8_t)compcode;
        goto EXIT;
    }

    uint8_t tail = compcode - 1;
    tail = ~tail;
    srcvalue = 0 - (int8_t)tail;

EXIT:
    return srcvalue;
}

// 求16位补码 compcode 的原值
int16_t Complement_to_I16(uint16_t compcode)
{
    int16_t srcvalue;

    uint16_t head = compcode & 0x8000;
    if (head == 0)
    {
        srcvalue = (int16_t)compcode;
        goto EXIT;
    }

    uint16_t tail = compcode - 1;
    tail = ~tail;
    srcvalue = 0 - (int16_t)tail;

EXIT:
    return srcvalue;
}

// 求32位补码 compcode 的原值
int32_t Complement_to_I32(uint32_t compcode)
{
    int32_t srcvalue;

    uint32_t head = compcode & 0x80000000;
    if (head == 0)
    {
        srcvalue = (int32_t)compcode;
        goto EXIT;
    }

    uint32_t tail = compcode - 1;
    tail = ~tail;
    srcvalue = 0 - (int32_t)tail;

EXIT:
    return srcvalue;
}

程序验证

我找到了一个求原码、反码、补码的在线工具,亲测靠谱,给大家推荐一下网址:https://www.lddgo.net/convert/number-binary-code

我用 CUnit 写了一些单元测试,来验证我上述提供的这些求补码的函数及其逆运算函数的正确性。我就不在这里科普 CUnit 的基本用法了,直接贴相关的单元测试代码。

单元测试程序的头文件

#ifndef _INC_UNITTETST_CUNIT_COMMFUNC_TESTCASES_COMMONFUNC_TS_A001_Common_H
#define _INC_UNITTETST_CUNIT_COMMFUNC_TESTCASES_COMMONFUNC_TS_A001_Common_H

#define TS_A001_Identifier "TS_A001: Bit Operation"

#ifdef __cplusplus
extern "C" {
#endif

    int TS_A001_Setup(void);
    int TS_A001_Cleanup(void);

    // 验证 I8_to_Complement 函数对输入参数`srcvalue`为0或正整数时工作正常
    void TC0001_I8_to_Complement_PositiveInteger();

    // 验证 I8_to_Complement 函数对输入参数`srcvalue`为负整数时工作正常
    void TC0002_I8_to_Complement_NegativeInteger();

    // 验证 Complement_to_I8 函数对 TC0001 和 TC0002 中的正/负整数求得的补码,都能逆向求得其原始值(正/负整数)
    void TC0003_Complement_to_I8();

    // 验证 I16_to_Complement 函数对输入参数`srcvalue`为0或正整数时工作正常
    void TC0004_I16_to_Complement_PositiveInteger();

    // 验证 I16_to_Complement 函数对输入参数`srcvalue`为负整数时工作正常
    void TC0005_I16_to_Complement_NegativeInteger();

    // 验证 Complement_to_I16 函数对 TC0004 和 TC0005 中的正/负整数求得的补码,都能逆向求得其原始值(正/负整数)
    void TC0006_Complement_to_I16();

    // 验证 I32_to_Complement 函数对输入参数`srcvalue`为0或正整数时工作正常
    void TC0007_I32_to_Complement_PositiveInteger();

    // 验证 I32_to_Complement 函数对输入参数`srcvalue`为负整数时工作正常
    void TC0008_I32_to_Complement_NegativeInteger();

    // 验证 Complement_to_I32 函数对 TC0007 和 TC0008 中的正/负整数求得的补码,都能逆向求得其原始值(正/负整数)
    void TC0009_Complement_to_I32();

#ifdef __cplusplus
} // ! extern "C"
#endif

#endif // !_INC_UNITTETST_CUNIT_COMMFUNC_TESTCASES_COMMONFUNC_TS_A001_Common_H

单元测试程序的测试用例实现

#include "CUnit/CUnit.h"
#include "Common/CommonFuncs.h"

#include "TS_A001_Common.h"


// ----------------------------------------------------------------------
// Public functions implementation
// ----------------------------------------------------------------------

int TS_A001_Setup(void)
{
    return CUE_SUCCESS;
}

int TS_A001_Cleanup(void)
{
    return CUE_SUCCESS;
}

// ========================================================
// 参考:在线原码/反码/补码计算器
// https://www.lddgo.net/convert/number-binary-code
// ========================================================


// 验证 I8_to_Complement 函数对输入参数`srcvalue`为0或正整数时工作正常
void TC0001_I8_to_Complement_PositiveInteger()
{
#define TC0001_VARS_COUNT 3
    int8_t SrcValues[TC0001_VARS_COUNT] = {
        0, 1, 127
    };

    uint8_t CompCodes[TC0001_VARS_COUNT] = {
        0, 1, 0x7F
    };

    for (int idx = 0; idx < TC0001_VARS_COUNT; idx++)
    {
        uint8_t compcode = I8_to_Complement(SrcValues[idx]);
        CU_ASSERT_EQUAL(compcode, CompCodes[idx]);
    }
}


// 验证 I8_to_Complement 函数对输入参数`srcvalue`为负整数时工作正常
void TC0002_I8_to_Complement_NegativeInteger()
{
#define TC0002_VARS_COUNT 6
    int8_t SrcValues[TC0002_VARS_COUNT] = {
        -1, -3, -63, -64, -127, -128
    };

    uint8_t CompCodes[TC0002_VARS_COUNT] = {
        0xFF, 0xFD, 0xC1, 0xC0, 0x81, 0x80
    };

    for (int idx = 0; idx < TC0002_VARS_COUNT; idx++)
    {
        uint8_t compcode = I8_to_Complement(SrcValues[idx]);
        CU_ASSERT_EQUAL(compcode, CompCodes[idx]);
    }
}


// 验证 Complement_to_I8 函数对 TC0001 和 TC0002 中的正/负整数求得的补码,都能逆向求得其原始值(正/负整数)
void TC0003_Complement_to_I8()
{
#define TC0003_VARS_COUNT 9
    int8_t SrcValues[TC0003_VARS_COUNT] = {
        0, 1, 127,
        -1, -3, -63, -64, -127, -128
    };

    uint8_t CompCodes[TC0003_VARS_COUNT] = {
        0, 1, 0x7F,
        0xFF, 0xFD, 0xC1, 0xC0, 0x81, 0x80
    };

    for (int idx = 0; idx < TC0003_VARS_COUNT; idx++)
    {
        int8_t srcValue = Complement_to_I8(CompCodes[idx]);
        CU_ASSERT_EQUAL(srcValue, SrcValues[idx]);
    }
}


// 验证 I16_to_Complement 函数对输入参数`srcvalue`为0或正整数时工作正常
void TC0004_I16_to_Complement_PositiveInteger()
{
#define TC0004_VARS_COUNT 7
    int16_t SrcValues[TC0004_VARS_COUNT] = {
        0, 1, 127, 128, 255,
        256, 32767
    };

    uint16_t CompCodes[TC0004_VARS_COUNT] = {
        0, 1, 0x7F, 0x80, 0xFF,
        0x0100, 0x7FFF
    };

    for (int idx = 0; idx < TC0004_VARS_COUNT; idx++)
    {
        uint16_t compcode = I16_to_Complement(SrcValues[idx]);
        CU_ASSERT_EQUAL(compcode, CompCodes[idx]);
    }
}


// 验证 I16_to_Complement 函数对输入参数`srcvalue`为负整数时工作正常
void TC0005_I16_to_Complement_NegativeInteger()
{
#define TC0005_VARS_COUNT 12
    int16_t SrcValues[TC0005_VARS_COUNT] = {
        -1, -3, -63, -64, -127, -128, -129, -255, -256,
        -257,
        -32767, -32768
    };

    uint16_t CompCodes[TC0005_VARS_COUNT] = {
        0xFFFF, 0xFFFD, 0xFFC1, 0xFFC0, 0xFF81, 0xFF80, 0xFF7F, 0xFF01, 0xFF00,
        0xFEFF,
        0x8001, 0x8000
    };

    for (int idx = 0; idx < TC0005_VARS_COUNT; idx++)
    {
        uint16_t compcode = I16_to_Complement(SrcValues[idx]);
        CU_ASSERT_EQUAL(compcode, CompCodes[idx]);
    }
}


// 验证 Complement_to_I16 函数对 TC0004 和 TC0005 中的正/负整数求得的补码,都能逆向求得其原始值(正/负整数)
void TC0006_Complement_to_I16()
{
#define TC0006_VARS_COUNT 19
    int16_t SrcValues[TC0006_VARS_COUNT] = {
        0, 1, 127, 128, 255,
        256, 32767,
        -1, -3, -63, -64, -127, -128, -129, -255, -256,
        -257,
        -32767, -32768
    };

    uint16_t CompCodes[TC0006_VARS_COUNT] = {
        0, 1, 0x7F, 0x80, 0xFF,
        0x0100, 0x7FFF,
        0xFFFF, 0xFFFD, 0xFFC1, 0xFFC0, 0xFF81, 0xFF80, 0xFF7F, 0xFF01, 0xFF00,
        0xFEFF,
        0x8001, 0x8000
    };

    for (int idx = 0; idx < TC0006_VARS_COUNT; idx++)
    {
        int16_t srcValue = Complement_to_I16(CompCodes[idx]);
        CU_ASSERT_EQUAL(srcValue, SrcValues[idx]);
    }
}


// 验证 I32_to_Complement 函数对输入参数`srcvalue`为0或正整数时工作正常
void TC0007_I32_to_Complement_PositiveInteger()
{
#define TC0007_VARS_COUNT 3
    int32_t SrcValues[TC0007_VARS_COUNT] = {
        0, 1, 0x7FFFFFFF
    };

    uint32_t CompCodes[TC0007_VARS_COUNT] = {
        0, 1, 0x7FFFFFFF
    };

    for (int idx = 0; idx < TC0007_VARS_COUNT; idx++)
    {
        uint32_t compcode = I32_to_Complement(SrcValues[idx]);
        CU_ASSERT_EQUAL(compcode, CompCodes[idx]);
    }
}


// 验证 I32_to_Complement 函数对输入参数`srcvalue`为负整数时工作正常
#if defined(_WIN32) && defined(_MSC_VER)
#pragma warning(disable: 4146)
#endif
void TC0008_I32_to_Complement_NegativeInteger()
{
#define TC0008_VARS_COUNT 4
    
    // 2147483647(DEC): 0x7FFFFFFF
    // 2147483648(DEC): 0x80000000
    int32_t SrcValues[TC0008_VARS_COUNT] = {
        -1, -2, -2147483647, -2147483648
    };

    uint32_t CompCodes[TC0008_VARS_COUNT] = {
        0xFFFFFFFF, 0xFFFFFFFE, 0x80000001, 0x80000000
    };

    for (int idx = 0; idx < TC0008_VARS_COUNT; idx++)
    {
        uint32_t compcode = I32_to_Complement(SrcValues[idx]);
        CU_ASSERT_EQUAL(compcode, CompCodes[idx]);
    }
}


// 验证 Complement_to_I32 函数对 TC0007 和 TC0008 中的正/负整数求得的补码,都能逆向求得其原始值(正/负整数)
#if defined(_WIN32) && defined(_MSC_VER)
#pragma warning(disable: 4146)
#endif
void TC0009_Complement_to_I32()
{
#define TC0009_VARS_COUNT 7
    int32_t SrcValues[TC0009_VARS_COUNT] = {
        0, 1, 0x7FFFFFFF,
        -1, -2, -2147483647, -2147483648
    };

    uint32_t CompCodes[TC0009_VARS_COUNT] = {
        0, 1, 0x7FFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFE, 0x80000001, 0x80000000
    };

    for (int idx = 0; idx < TC0009_VARS_COUNT; idx++)
    {
        int32_t srcValue = Complement_to_I32(CompCodes[idx]);
        CU_ASSERT_EQUAL(srcValue, SrcValues[idx]);
    }
}

单元测试的运行结果

通过单元测试,验证了程序的正确性。截图如下:
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1823371.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis-Plus整合达梦数据库

文章目录 1. 环境准备2. 创建Spring Boot项目3. 引入依赖4. 配置数据源5. 配置MyBatis-Plus6. 创建实体类7. 创建Mapper接口8. 创建Service类9. 创建Controller类10. 创建Mapper XML文件11. 测试12. 进一步优化12.1 配置分页插件12.2 配置乐观锁插件13. 总结🎉欢迎来到Java学…

vue+elementui+springboot图片上传

1、前端代码 <template><div><el-uploadclass"avatar-uploader"action"http://localhost:8081/ch06/demo/uploadAvatar":show-file-list"false":on-success"handleAvatarSuccess":before-upload"beforeAvatarUpl…

SIGMOD 2024 | 时空数据(Spatial-Temporal)和时间序列(Time Series)论文总结

SIGMOD2024于6月9号-6月14号正在智利圣地亚戈举行&#xff08;Santiago Chile&#xff09; 本文总结了SIGMOD 2024有关时间序列&#xff08;time series&#xff09;,包括时序数据库&#xff0c;查询优化等内容。以及时空数据&#xff08;spatial-temporal data&#xff09;的…

【Vue】自学笔记(四)

上一篇&#xff1a;Vue笔记&#xff08;三&#xff09;-CSDN博客 1.VueCli自定义搭建项目 先确保安装了全局工具VueCli 如果没有&#xff0c;则先运行命令 npm i vue/cli -g 选择最后一个自定义搭建项目 选择需要自动搭建的功能 这里我需要router和css预处理器就空格勾选上&…

干货!电脑如何录屏?6款win10录屏大师软件深度测评

电脑如何录屏&#xff1f;在2024年&#xff0c;截图或屏幕录制可以说是一种无价的工具。它是捕捉重要信息、与朋友和同事分享说明&#xff0c;或者只是存储您最喜爱的游戏和应用程序中的记忆的好方法。在 Windows 上录制屏幕非常简单。在本篇文章中&#xff0c;我们将讨论在win…

Node入门以及express创建项目

前言 记录学习NodeJS 一、NodeJS是什么&#xff1f; Node.js 是一个开源和跨平台的 JavaScript 运行时环境 二、下载NodeJs 1.下载地址(一直点击next即可&#xff0c;记得修改安装地址) https://nodejs.p2hp.com/download/ 2.查看是否安装成功&#xff0c;打开命令行 nod…

InfoComm 2024 直击:千视新品P3和KiloLink技术闪耀亮相

InfoComm 2024 直击&#xff1a;千视新品P3和KiloLink技术闪耀亮相&#xff0c;现场亮点不断 北京时间2024年6月13日&#xff0c;UTC-7时间6月12日&#xff0c;美国视听显示与系统集成展览会InfoComm 2024在美国拉斯维加斯正式开幕。作为全美规模最大、最具影响力的展会&#…

电脑数字键被锁住不能输入数字

情况: 反复点击数字键盘的NumLock,看它的灯是否能正常启动 1.如果NumLock灯可以正常的打开和关闭,并且无法输入内容 1.1打开控制面板 1.2 进入轻松使用中选择更改键盘的工作方式 1.3找到并点击设置鼠标键 1.4 赵到NumLock设置为关闭,然后确定即可

辽宁省食品安全管理人员精选模拟试题

新增(食品安全法实施条例)相关真题16道&#xff0c;具体如下: 1.食品生产企业可以制定低于食品安全标准或者地方标准要求的企业标准。(X) 2.食品生产者应当建立食品安全追溯体系&#xff0c;保证食品可追溯。(√) 3.食品生产企业的主要负责人对本企业的食品安全工作全面负责&am…

Java注解Annotation机制说明和基础使用(为什么Annotation直接促进了框架的繁荣发展?)

一、注解解决的问题【可忽略】 软件开发过程中&#xff0c;如何配置一直是一个重要的问题&#xff0c;对于一个框架&#xff0c;如果你不为它提供初始结构&#xff0c;它就无法理解你要做什么&#xff0c;自然无法工作。 1.问题&#xff1a;紧密贴合的代码和配置 在很久之前…

One能聊天接入百度千帆AppBuilder

One能聊天介绍:基于ChatGPT实现的微信小程序,适配H5和WEB端。包含前后端,支持打字效果输出流式输出,支持AI聊天次数限制,支持分享增加次数等功能One能聊天开源地址:https://github.com/oldinaction/ChatGPT-MPOne能聊天演示环境:可关注【阿壹族】公众号,并回复【One能聊…

spring框架(SSM)

Spring Framework系统架构 Spring框架是一个开源的企业级Java应用程序框架&#xff0c;它为开发Java应用程序提供了一个全方位的解决方案。Spring的核心优势在于它的分层架构&#xff0c;这使得开发者可以灵活选择使用哪些模块而无需引入不需要的依赖。下面是Spring框架的一些关…

Cisco Packet Tracer实验(三)

续实验二 问题一&#xff1a;使用二层交换机连接的网络需要配置网关吗&#xff1f;为什么&#xff1f; 二层交换机作为网络设备中的一种&#xff0c;主要用于在局域网&#xff08;LAN&#xff09;内部进行数据包的转发。它工作在OSI模型的第二层&#xff08;数据链路层&#xf…

08_基于GAN实现人脸图像超分辨率重建实战_超分辨基础理论

1. 超分辨的概念与应用 我们常说的图像分辨率指的是图像长边像素数与图像短边像素数的乘积,比如iPhoneX手机拍摄照片的分辨率为 4032px3024px,为1200万像素。 显然,越高的分辨率能获得更清晰的成像。与之同时,分辨率越高也意味着更大的存储空间,对于空间非常有限的移动设…

Embedding 模型的选择和微调

构建一个检索增强生成 (Retrieval-Augmented Generation, RAG) 应用的概念验证过程相对简单&#xff0c;但要将其推广到生产环境中则会面临多方面的挑战。 『RAG 高效应用指南』系列将就如何提高 RAG 系统性能进行深入探讨&#xff0c;提供一系列具体的方法和建议。同时读者也需…

StableSwarmUI 安装教程(详细)

文章目录 背景特点安装 背景 StableSwarmUI是StabilityAI官方开源的一个文生图工作流UI&#xff0c;目前处于beta阶段&#xff0c;但主流程是可以跑通的。该UI支持接入ComfyUI、Stable Diffusion-WebUI。其工作原理就是使用ComfyUI、Stable Diffusion-WebUI或者StabilityAI官方…

张艺兴step新专开启自由驾驶新纪元

张艺兴《Step》新专&#xff0c;开启自由驾驶新纪元&#xff01;当音乐与驾驶相遇&#xff0c;会碰撞出怎样的火花&#xff1f;当实力派艺人张艺兴遇上全新英文专辑《Step》&#xff0c;便为我们解锁了一种前所未有的出行体验&#xff01;这不仅仅是一张音乐专辑&#xff0c;更…

英伟达GPU对比分析:A100、A800、H100与H800

在当今技术迅速发展的时代&#xff0c;英伟达的GPU产品线提供了多种高性能选项&#xff0c;以满足不同类型的工作负载需求。本文将对英伟达的四种GPU型号——A100、A800、H100和H800进行深入对比分析&#xff0c;探讨它们在性能、架构、应用场景等方面的差异&#xff0c;以帮助…

Redis原理篇——分布式锁

Redis原理篇——分布式锁 分布式锁是什么&#xff1f;分布式锁有哪些特性&#xff1f;分布式锁常用实现方式Redis 实现分布式锁一、简单的 Redis 锁二、带过期时间的 Redis 锁三、加上 Owner 的 Redis 锁四、Lua 脚本确保原子性 分布式锁是什么&#xff1f; 分布式锁是在分布式…

HTML解析之Beautiful Soup

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Beautiful Soup是一个用于从HTML和XML文件中提取数据的Python库。Beautiful Soup 提供一些简单的、函数用来处理导航、搜索、修改分析树等功能。Beau…