มีวิธีใดในการเขียนฟังก์ชันบันทึก (ฐาน 2) หรือไม่?
ภาษา C มี 2 ฟังก์ชันในตัว - >>
1. log
ซึ่งเป็นฐาน e.
2. log10
ฐาน 10;
แต่ฉันต้องการฟังก์ชันบันทึกของฐาน 2 วิธีคำนวณสิ่งนี้
มีวิธีใดในการเขียนฟังก์ชันบันทึก (ฐาน 2) หรือไม่?
ภาษา C มี 2 ฟังก์ชันในตัว - >>
1. log
ซึ่งเป็นฐาน e.
2. log10
ฐาน 10;
แต่ฉันต้องการฟังก์ชันบันทึกของฐาน 2 วิธีคำนวณสิ่งนี้
คำตอบ:
คณิตศาสตร์ง่ายๆ:
บันทึก2 ( x ) = บันทึกy ( x ) / บันทึกy (2)
ที่ปีสามารถเป็นอะไรก็ได้ซึ่งสำหรับฟังก์ชั่นบันทึกมาตรฐานเป็นทั้ง 10 หรืออี
C99 มีlog2
(เช่นเดียวกับlog2f
และlog2l
สำหรับลอยและคู่ยาว)
หากคุณกำลังมองหาผลลัพธ์ที่สำคัญคุณสามารถกำหนดบิตสูงสุดที่ตั้งไว้ในค่าและส่งคืนตำแหน่งได้
Integer.highestOneBit(int)
วิธีการของ Java ):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
while (i >>= 1) { ++l; }
i>>32
บิตมันจะมีเป็นพิเศษ แต่เนื่องจาก Java มี ints เพียง 32 บิตจึงใช้ได้ สำหรับ C / C ++ จำเป็นต้องพิจารณา
#define M_LOG2E 1.44269504088896340736 // log2(e)
inline long double log2(const long double x){
return log(x) * M_LOG2E;
}
(การคูณอาจเร็วกว่าการหาร)
log2(int n) = 31 - __builtin_clz(n)
ตามที่ระบุไว้ในhttp://en.wikipedia.org/wiki/Logarithm :
logb(x) = logk(x) / logk(b)
ซึ่งหมายความว่า:
log2(x) = log10(x) / log10(2)
log()
การนำไปใช้งานจึงจะไม่ทำ ความผิดฉันเอง.
log10()
เป็นฟังก์ชันที่กำหนดไว้ในมาตรฐาน C คอมไพเลอร์จึงมีอิสระที่จะปฏิบัติต่อ "พิเศษ" รวมถึงการคำนวณผลลัพธ์ล่วงหน้าซึ่งฉันเชื่อว่าเป็นคำแนะนำของ @Johannes
log10(2)
ด้วยค่าคงที่
หากคุณต้องการทำให้เร็วคุณสามารถใช้ตารางค้นหาเช่นในBit Twiddling Hacks (log2 จำนวนเต็มเท่านั้น)
uint32_t v; // find the log base 2 of 32-bit v
int r; // result goes here
static const int MultiplyDeBruijnBitPosition[32] =
{
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
v |= v >> 1; // first round down to one less than a power of 2
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
r = MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];
นอกจากนี้คุณควรดูวิธีการในตัวของคอมไพเลอร์_BitScanReverse
ซึ่งอาจเร็วกว่าเนื่องจากอาจคำนวณทั้งหมดในฮาร์ดแวร์
ลองดูการทำซ้ำที่เป็นไปได้วิธีทำ log2 จำนวนเต็ม () ใน C ++ ได้อย่างไร?
uint16_t log2(uint32_t n) {//but truncated
if (n==0) throw ...
uint16_t logValue = -1;
while (n) {//
logValue++;
n >>= 1;
}
return logValue;
}
โดยทั่วไปเช่นเดียวกับtomlogic 's
คุณต้องรวม math.h (C) หรือ cmath (C ++) แน่นอนว่าคุณต้องทำตามคณิตศาสตร์ที่เรารู้ ... เฉพาะตัวเลข> 0
ตัวอย่าง:
#include <iostream>
#include <cmath>
using namespace std;
int main(){
cout<<log2(number);
}
ฉันต้องการให้มีความแม่นยำมากขึ้นซึ่งเพียงแค่ตำแหน่งของบิตที่สำคัญที่สุดและไมโครคอนโทรลเลอร์ที่ฉันใช้ไม่มีห้องสมุดคณิตศาสตร์ ฉันพบว่าเพียงแค่ใช้การประมาณเชิงเส้นระหว่างค่า 2 ^ n สำหรับอาร์กิวเมนต์ค่าจำนวนเต็มบวกก็ใช้ได้ดี นี่คือรหัส:
uint16_t approx_log_base_2_N_times_256(uint16_t n)
{
uint16_t msb_only = 0x8000;
uint16_t exp = 15;
if (n == 0)
return (-1);
while ((n & msb_only) == 0) {
msb_only >>= 1;
exp--;
}
return (((uint16_t)((((uint32_t) (n ^ msb_only)) << 8) / msb_only)) | (exp << 8));
}
ในโปรแกรมหลักของฉันฉันต้องคำนวณ N * log2 (N) / 2 ด้วยผลลัพธ์จำนวนเต็ม:
อุณหภูมิ = (((uint32_t) N) * ประมาณ _log_base_2_N_times_256) / 512;
และค่า 16 บิตทั้งหมดไม่เคยปิดเกิน 2%
คำตอบทั้งหมดข้างต้นถูกต้อง คำตอบของฉันด้านล่างนี้จะเป็นประโยชน์หากมีคนต้องการ ฉันเห็นข้อกำหนดนี้ในคำถามมากมายที่เรากำลังแก้โดยใช้ C
log2 (x) = logy (x) / logy (2)
อย่างไรก็ตามหากคุณใช้ภาษา C และต้องการให้ผลลัพธ์เป็นจำนวนเต็มคุณสามารถใช้สิ่งต่อไปนี้:
int result = (int)(floor(log(x) / log(2))) + 1;
หวังว่านี่จะช่วยได้
log n / log 2
ปรึกษาพื้นฐานทางคณิตศาสตร์ของคุณแน่นอน ไม่สำคัญว่าคุณจะเลือกlog
หรือlog10
ในกรณีนี้การหารด้วยlog
ฐานใหม่จะเป็นเคล็ดลับ
เวอร์ชันปรับปรุงของสิ่งที่ Ustaman Sangat ทำ
static inline uint64_t
log2(uint64_t n)
{
uint64_t val;
for (val = 0; n > 1; val++, n >>= 1);
return val;
}