16 비트 * 32 비트 연산을 원하지만 32 비트 레지스터 만 사용하고 싶습니다. 출력은 48 비트이기 때문에 두 개의 32 비트 레지스터로 결과를 포착 할 수 있습니다. 이 문제의 C 코드를 원합니다! 64 비트 출력 기능을 가진 32 비트 * 32 비트 MUL을 가지고 있지만 신호 때문에이 기능을 제대로 사용할 수 없습니다. exapmle 16 비트에서 1을 뺀 값은 0xFFFF이고 32 비트에서 1을 뺀 값은 0xFFFFFFFF입니다. 이 코드는 MUL의 LLVM 번역에 사용됩니다.48 비트 결과를 가진 16 비트 * 32 비트 MUL
답변
이와 비슷한 작업을하려고하십니까?
#include <inttypes.h>
void multiply(uint16_t*top,uint32_t*bottom, uint16_t lhs,uint32_t rhs){
uint32_t low=lhs*(rhs&0xFFFF);
uint32_t high=lhs*(rhs>>16)+(low>>16);
*bottom=(high)<<16)|(low&0xFFFF);
*top=(high>>16);
}
당신은 모든 기본 65536 (** 16 2)에서 두 자리 숫자 한 자리 수를 곱하고 실현하면 그것은 훨씬 더 쉽다.
출력을 확인하고 표시하기 위해 64 비트 만 사용했습니다. 곱셈은 32 비트에서 작동합니다.
여기는 테스트 하니스에 : 여기
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
void multiply(uint16_t*top,uint32_t*bottom, uint16_t lhs,uint32_t rhs){
uint32_t low=lhs*(rhs&0xFFFF);
uint32_t high=lhs*(rhs>>16)+(low>>16);
*bottom=(high)<<16)|(low&0xFFFF);
*top=(high>>16);
}
uint64_t encode64(uint16_t top,uint32_t bottom){
return (((uint64_t)top)<<32)|((uint64_t)bottom);
}
int check(uint16_t lhs,uint32_t rhs){
uint16_t t16;
uint32_t t32;
multiply(&t16,&t32,lhs,rhs);
const uint64_t result=encode64(t16,t32);
uint64_t llhs=lhs;
uint64_t lrhs=rhs;
uint64_t expect=llhs*lrhs;
if(result==expect){
return 0;
}
printf("%"PRIu16"*%"PRIu32"==%"PRIu64"!=%"PRIu64"\n",lhs,rhs,result,expect);
return 1;
}
int main(void) {
int error=0;
uint16_t top;
uint32_t bottom;
uint16_t lhs=58989;
uint32_t rhs=5978342;
error+=check(2U,20UL);
error+=check(0xFFFF,0xFFFFFFFF);
error+=check(768U,565354767UL);
error+=check(26434U,566534767UL);
error+=check(26434U,690789UL);
error+=check(5678U,9767889UL);
error+=check(3674U,784367UL);
error+=check(0,690789ULL);
error+=check(0,0xFFFFFFFF);
error+=check(0xFFFF,0);
error+=check(0xFFFF,1);
error+=check(1,0xFFFFFFFF);
error+=check(0x2,0xAFFFFFFF);
multiply(&top,&bottom,lhs,rhs);
uint64_t result=encode64(top,bottom);
printf("%"PRIu16"*%"PRIu32"==%"PRIu64"\n",lhs,rhs,result);
if(error!=0){
printf("\nErrors=%d\n",error);
}
return error==0?EXIT_SUCCESS:EXIT_FAILURE;
}
이것은 나를 위해 일하고있다 ... 고마워 :) –
16 비트 레지스터를 32 비트 레지스터로 부호 확장 한 다음 부호있는 32 비트 x 32 비트 곱셈을 사용하십시오.
고마워. 그게 나를 위해 일했다. 내 어리석은 누락;) –
어려운 부분은 이전 버전의 C 언어 (*) ... 및 int, long 및 long long에서 명시 적으로 정의되지 않았기 때문에 16 비트, 32 비트 및 64 비트 정수가 어떻게 정의되는지를 아는 것입니다 그런 식으로.
은 당신이 int32_t와 int64_t, 당신이 할 수있는, int16_t 있다고 가정
int64_t product16_35(int16_t val1, int32_t val2) {
int64_t v1 = val1, v2 = val2, resul;
resul = v1 * v2; /* resul uses 48 bits on 64, with sign extended to 64 bits */
resul &= 0x00FFFFFFFFFFFFFF; /* truncate resul at 48 bits */
return resul;
}
(*) 그것은 C99의 일부입니다 만> 2010 년
편집 OP 코멘트 당 MSVC에서 제공
하나의 16 비트 정수 (상위 부분)와 하나의 32 비트 정수로 결과를 얻으려면 위의 약간의 차이가 있습니다.
struct int48 {
int16_t h;
uint32_t l; /* sign has no sense for lower part */
}
int48 product16_35(int16_t val1, int32_t val2) {
int48 res48;
int64_t v1 = val1, v2 = val2, resul;
resul = v1 * v2; /* resul uses 48 bits on 64, with sign extended to 64 bits */
resul &= 0x00FFFFFFFFFFFFFF; /* truncate resul at 48 bits */
res48.l = resul & 0xFFFFFFFF;
res48.h = (resul >> 32) & 0xFFFF;
return res48;
}
물론 32 비트 연산과 시프트를 사용하여 제품 16 비트 * 32 비트를 직접 처리 할 수도 있습니다. 하지만 컴파일러가 64 비트 연산을 직접 수행하는 것보다 효율적이지는 않습니다.
당신은 64 비트 정수를 사용했습니다 ... 난 그냥 32 비트 정수를 사용하여 그것을하고 싶습니다. 마찬가지로 몇 가지 계산을 마치 한 변수에서 32 비트 오른쪽 및 다른 변수에서 16 비트 얻을 –
@ ZeeshanHaider 어셈블리 언어에서 2 32 비트 레지스터를 곱하는 방법을 알고 64 비트 확장 된 레지스터에서 결과를 얻을. 하지만 C 언어에서 결과에 32 자리 이상을 사용하려면 64 비트 정수를 사용해야합니다. 하지만 내 편집도 참조하십시오. –
감사합니다.위의 언급 된 언급은 나를 위해 일하지만 나는 또한 당신의 제안을 시도 할 것이다 :) –
32 * 32 MUL이다. 누군가가 LLVM을 이해하면 도움이 될 것입니다. 16 비트 부호 확장을위한 다음이 기능.
/*static*/
enum bin2vm_status_codes bin2vm::IrModuleWriter::getSignedMul32_Result64bit(llvm::Value* tempFirstOp,llvm::Value* tempSecondOp,llvm::Value** result_Right32,llvm::Value** result_Left32, IRBuilder* irBuilder)
{
enum bin2vm_status_codes status = BIN2VM_STATUS_SUCCESS;
oef_debug_print(("bin2vm::IrModuleWriter::getSignedMul32_Result64bit(): ENTERED\n"));
llvm::Value* Op1IsNeg = nullptr;
llvm::Value* bool_Op1IsNeg = nullptr;
llvm::Value* Op2IsNeg = nullptr;
llvm::Value* bool_Op2IsNeg = nullptr;
llvm::ConstantInt* int32One = irBuilder->getInt32(1);
llvm::Value* finalResult_right32 = nullptr;
llvm::Value* bool_bothNeg = nullptr;
llvm::Value* firstOp_right = nullptr;
llvm::Value* firstOp_left = nullptr;
llvm::Value* secondOp_right = nullptr;
llvm::Value* secondOp_left = nullptr;
llvm::Value* partialProduct_0 = nullptr;
llvm::Value* partialProduct_1 = nullptr;
llvm::Value* partialProduct_2 = nullptr;
llvm::Value* partialProduct_3 = nullptr;
llvm::Value* partialProduct_1_left = nullptr;
llvm::Value* partialProduct_1_right = nullptr;
llvm::Value* partialProduct_2_left = nullptr;
llvm::Value* partialProduct_2_right = nullptr;
llvm::Value* sumPartial_temp = nullptr;
llvm::Value* sumPartial = nullptr;
llvm::Value* finalResult_left32 = nullptr;
llvm::Value* sumPartial_op1Neg = nullptr;
llvm::Value* sumPartial_op2Neg = nullptr;
llvm::Value* sumPartial_bothNeg = nullptr;
llvm::Value* bothNeg = nullptr;
//Mul operation
finalResult_right32 = irBuilder->CreateMul(tempFirstOp,tempSecondOp,"mulResult");
//Calculation for left 32 bits
//Can have a look at http://stackoverflow.com/questions/22845801/32-bit-signed-multiplication-without-using-64-bit-data-type
firstOp_right = irBuilder->CreateAnd(tempFirstOp,0x0000FFFF,"firstOp_right");
firstOp_left = irBuilder->CreateLShr(tempFirstOp, 16, "firstOp_left");
secondOp_right = irBuilder->CreateAnd(tempSecondOp,0x0000FFFF,"secondOp_right");
secondOp_left = irBuilder->CreateLShr(tempSecondOp, 16, "secondOp_left");
/* compute partial products */
partialProduct_0 = irBuilder->CreateMul(firstOp_right,secondOp_right,"partialProduct_0");
partialProduct_1 = irBuilder->CreateMul(firstOp_right,secondOp_left,"partialProduct_1");
partialProduct_2 = irBuilder->CreateMul(firstOp_left,secondOp_right,"partialProduct_2");
partialProduct_3 = irBuilder->CreateMul(firstOp_left,secondOp_left,"partialProduct_3");
partialProduct_0 = irBuilder->CreateLShr(partialProduct_0,16,"partialProduct_0");
partialProduct_1_left = irBuilder->CreateLShr(partialProduct_1,16,"partialProduct_1_left");
partialProduct_1_right = irBuilder->CreateAnd(partialProduct_1,0x0000FFFF, "partialProduct_1_right");
partialProduct_2_left = irBuilder->CreateLShr(partialProduct_2,16,"partialProduct_2_left");
partialProduct_2_right = irBuilder->CreateAnd(partialProduct_2,0x0000FFFF, "partialProduct_2_right");
//sumPartial_temp = ((p0 >> 16) + (uint16_t)p1 + (uint16_t)p2) >> 16
sumPartial_temp = irBuilder->CreateAdd(partialProduct_0,partialProduct_1_right,"sumPartial_temp");
sumPartial_temp = irBuilder->CreateAdd(sumPartial_temp,partialProduct_2_right,"sumPartial_temp");
sumPartial_temp = irBuilder->CreateLShr(sumPartial_temp,16,"sumPartial_temp");
// p3 + (p2 >> 16) + (p1 >> 16) + sumPartial_temp
sumPartial = irBuilder->CreateAdd(sumPartial_temp,partialProduct_3,"sumPartial");
sumPartial = irBuilder->CreateAdd(sumPartial,partialProduct_2_left,"sumPartial");
sumPartial = irBuilder->CreateAdd(sumPartial,partialProduct_1_left,"sumPartial");
//Now for signed Mul we look at sumPartial- ((op1 < 0) ? op2 : 0) - ((op2 < 0) ? op1 : 0)
sumPartial_op1Neg = irBuilder->CreateSub(sumPartial,tempSecondOp,"sumPartial_op1Neg");
sumPartial_op2Neg = irBuilder->CreateSub(sumPartial,tempFirstOp,"sumPartial_op2Neg");
sumPartial_bothNeg = irBuilder->CreateSub(sumPartial_op1Neg,tempFirstOp,"sumPartial_bothNeg");
//MUL signed adaptation
Op1IsNeg = irBuilder->CreateLShr(tempFirstOp,31,"bool_Op1IsNeg");
bool_Op1IsNeg = irBuilder->CreateICmpEQ(Op1IsNeg, int32One,"bool_Op1IsNeg");
Op2IsNeg = irBuilder->CreateLShr(tempSecondOp,31,"bool_Op2IsNeg");
bool_Op2IsNeg = irBuilder->CreateICmpEQ(Op2IsNeg, int32One,"bool_Op2IsNeg");
bothNeg = irBuilder->CreateAnd(Op1IsNeg,Op2IsNeg,"bothNeg");
bool_bothNeg = irBuilder->CreateICmpEQ(bothNeg,int32One,"bool_bothNeg");
//Resul left 32 bits
finalResult_left32 = irBuilder->CreateSelect(bool_Op1IsNeg,sumPartial_op1Neg,sumPartial);
finalResult_left32 = irBuilder->CreateSelect(bool_Op2IsNeg,sumPartial_op2Neg,finalResult_left32);
finalResult_left32 = irBuilder->CreateSelect(bool_bothNeg,sumPartial_bothNeg,finalResult_left32);
*result_Right32 = finalResult_right32;
*result_Left32 = finalResult_left32;
return status;
}
- 1. 16 비트 이미지에서 32 비트
- 2. 48 비트 키를 16 비트 값으로 해싱
- 3. Javascript에서 48 비트 비트 연산?
- 4. NASM 16 비트 및 32 비트
- 5. C++ 비트 연산 16, 32 비트 순간에
- 6. 16 비트 시스템에서 32 비트 정수가 가능합니까?
- 7. 32 비트 16 진수의 첫 번째 16 비트
- 8. 16 비트 비트 심도
- 9. 32 비트 64 비트 호환
- 10. 32 비트/64 비트 OS?
- 11. 32 비트 OS에서는 16 비트, 64 비트 OS에서는 32 비트의 데이터 유형은 무엇입니까?
- 12. 16 비트 포트 주소에 대한 32 비트 할당
- 13. 16 비트 디스플레이를 사용하는 장치의 32 비트 PNG 이미지
- 14. nasm과 32 비트 및 16 비트 코드 믹싱
- 15. Windows 7 64 비트에서 32 비트 프로세스에 16 비트 DLL로드
- 16. 16 비트를 사용하여 32 비트 값에서 비트 시프트 구현
- 17. C++ 32/64 비트 시스템에서 16 비트 포인터 사용
- 18. 16 비트 루미넌스 값을 32 비트 RGB로 변환
- 19. 16 비트 프로그램이 32 비트 OS에서 가상 8086 모드로 실행됩니까?
- 20. PHP : 두 개의 16 비트 정수를 32 비트 정수로 결합
- 21. C#에서 16 비트 'short'를 32 비트 정수로 변환하려면 어떻게해야합니까?
- 22. 해시 32 비트 정수를 16 비트 정수로 변환 하시겠습니까?
- 23. 파이썬에서 16 비트 또는 32 비트 이미지 읽기
- 24. 16 비트 코드와 32 비트 코드를 연결할 수 있습니까?
- 25. char에 대한 비트 연산은 32 비트 결과를 얻습니다.
- 26. 48 비트 이미지 히스토그램 계산
- 27. 64 비트 대 32 비트 플랫폼의 보급
- 28. 어셈블리 : 32 비트 레지스터로 64 비트 곱하기
- 29. 우분투 11.10 64 비트 대 32 비트
- 30. 파이썬 - IEEE754 32 비트 마이크로 칩 32 비트 컨버터
"C 코드를 원한다"는 것은 C++에 태그를 지정하지 않는다는 의미입니다. – crashmstr
음수를 양수로 변환하고 부호없는 다중을 수행 한 다음 나중에 부호를 수정하십시오. –
나는 C 또는 C++ 일지라도 실제로는 논리를 원해. 아무렇지도 않다. –