AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77025197
Accepted
dscerutti
dscerutti
Asked: 2023-09-02 01:59:47 +0800 CST2023-09-02 01:59:47 +0800 CST 2023-09-02 01:59:47 +0800 CST

Esta conversão bit a bit é segura?

  • 772

Tenho uma situação em que preciso agrupar 16 bits em um número de 64 bits e depois lê-los como um número inteiro assinado no intervalo [ -32768, 32768 ). O método que escolhi para isso é calcular o número como um int assinado de 16 bits, convertê-lo imediatamente em um int não assinado de 16 bits e, em seguida, fazer o upcast para um int não assinado de 64 bits antes de executar a mudança de bit adequada para obter os 16 bits críticos no lugar apropriado.

Aqui está o pseudocódigo para criar o arranjo compactado de bits:

Given int x, y such that x - y >= -32768 and y - x < 32768;
const int MASK_POS = 45;
const unsigned short int u_s = x - y;
unsigned long long int ull_s = u_s;
ull_s <<= MASK_POS;

Aqui está o pseudocódigo para extrair a diferença nos números originais:

Given unsigned long long int ull_s with 16 bits encoding a signed integer in the 46th through 61st bits;
const unsigned short int u_s = ((ulls >> MASK_POS) & 0xffff);
const short int s_s = u_s;
const int difference_x_and_y = s_s;

Esta me parece uma maneira razoável de empacotar um número inteiro assinado e extraí-lo. Desconfio do comportamento específico da plataforma ao realizar mudanças de bits em números inteiros negativos, mas acho que converter para a forma não assinada do mesmo número de bits antes de atualizar o número de bits gerais no número e, ao contrário, extrair o não assinado inteiro com comprimento de bit desejado antes de converter para um inteiro com sinal de tamanho igual, será seguro.

(Caso alguém esteja curioso, haverá MUITO coisa acontecendo nos outros 48 bits desse número inteiro não assinado de 64 bits em que o material acaba - dos três bits mais altos aos 31 mais baixos e aos 14 do meio, tudo foi analisado. Certamente posso escrever alguns testes de unidade para garantir que esse comportamento se mantenha em qualquer arquitetura, mas se alguém puder ver uma falha agora, é melhor saber com antecedência. Obrigado!)

c++
  • 1 1 respostas
  • 86 Views

1 respostas

  • Voted
  1. Best Answer
    Jan Schultke
    2023-09-02T02:11:22+08:002023-09-02T02:11:22+08:00

    O que você está fazendo está perfeitamente bem. Desde C++ 20, inteiros assinados são obrigados a ter representação em complemento de dois, e todas as conversões assinadas/não assinadas são bem definidas e equivalentes a std::bit_cast. Mesmo antes disso, qualquer implementação de seu interesse se comportaria dessa maneira.

    No entanto, provavelmente seria melhor se você usasse tipos de largura fixa, já std::uint16_tque seu código depende muito de uma largura específica.

    struct quad {
        std::int16_t x, y, z, w;
    };
    
    inline std::uint64_t pack(quad q) {
        // Two-step conversion to std::uint16_t -> std::uint64_t
        // to avoid a sign extension when going directly to std::uint64_t.
        // Alternatively, mask each operand with 0xffff.
        return std::uint64_t{std::uint16_t(q.x)} <<  0
             | std::uint64_t{std::uint16_t(q.y)} << 16
             | std::uint64_t{std::uint16_t(q.z)} << 32
             | std::uint64_t{std::uint16_t(q.w)} << 48;
        // alternatively, if you don't care about relying on
        // platform endianness ...
        return std::bit_cast<std::uint64_t>(q); // note: only works if quad is unpadded
    }
    
    inline quad unpack(std::uint64_t x) {
        // just let implicit conversions do their thing
        return { x >> 0, x >> 16, x >> 32, x >> 48 };
        // once again, alternatively ...
        return std::bit_cast<quad>(x);
    }
    

    Você pode empacotar números inteiros assim, mas isso levanta a questão de por que você não poderia usar um structlike quaddiretamente. Nenhum compilador sensato adicionará preenchimento a quad, e você pode ter certeza disso com

    static_assert(sizeof(quad) == sizeof(std::uint64_t));
    

    O compilador também não tem permissão para reordenar os membros de quad, portanto, para todos os efeitos, você pode simplesmente agrupar números inteiros quadem vez de agrupá-los em um número inteiro.

    • 4

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve