C / c ++ में लॉग बेस (2) कैसे लिखें


98

क्या लॉग (बेस 2) फ़ंक्शन लिखने का कोई तरीका है?

C भाषा में 2 फ़ंक्शन हैं - >>

1. logजो बेस ई है।

2. log10आधार 10;

लेकिन मुझे इसकी गणना करने के लिए बेस 2.H की लॉग फ़ंक्शन की आवश्यकता है।


1
नेत्रगोलक संगणना के लिए, आधार 2 लघुगणक आधार 10 लघुगणक और प्राकृतिक लघुगणक के बराबर है। जाहिर है कि एक कार्यक्रम में अधिक सटीक (और तेज) संस्करण लिखना बेहतर है।
डेविड थॉर्नले

पूर्णांक के लिए, आप दाएं बिटशिफ्ट पर लूप कर सकते हैं, और 0. तक पहुंचने पर रुक सकते हैं। लूप काउंट लॉग का एक अनुमान है
बेसाइल स्टायरनेविच

जवाबों:


198

सरल गणित:

    log 2 ( x ) = log y ( x ) / log y (2)

जहां y कुछ भी हो सकता है, जो मानक लॉग फ़ंक्शंस के लिए 10 या ई है



53

यदि आप एक अभिन्न परिणाम की तलाश में हैं, तो आप केवल मूल्य में उच्चतम बिट सेट निर्धारित कर सकते हैं और इसकी स्थिति वापस कर सकते हैं।


27
इसके लिए एक अच्छी बिट-ट्विडलिंग विधि भी है (जावा की Integer.highestOneBit(int)विधि से ली गई ):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
जॉय

38
... याwhile (i >>= 1) { ++l; }
ली डैनियल क्रोकर

2
@ जोय पूर्णांक मान 32 बिट चौड़ा है, नहीं काम करेगा? 64 बिट के लिए यह एक अतिरिक्त होगा i>>32। लेकिन चूंकि जावा में केवल 32-बिट इनट्स हैं, यह ठीक है। C / C ++ के लिए इस पर विचार करने की आवश्यकता है।
जोसो

43
#define M_LOG2E 1.44269504088896340736 // log2(e)

inline long double log2(const long double x){
    return log(x) * M_LOG2E;
}

(गुणा भाग विभाजन से तेज हो सकता है)


1
बस स्पष्ट करना चाहता था - लॉग रूपांतरण नियम + तथ्य का उपयोग करते हुए कि log_2 (e) = 1 / log_e (2) -> हमें परिणाम मिलता है
लड़के L


9

जैसा कि http://en.wikipedia.org/wiki/Logarithm पर बताया गया है :

logb(x) = logk(x) / logk(b)

जिसका अर्थ है कि:

log2(x) = log10(x) / log10(2)

11
ध्यान दें कि आप प्रदर्शन को बढ़ाने के लिए log10 (2) को रोक सकते हैं।
corsiKa

@ जोहान्स: मुझे संदेह है कि कंपाइलर लॉग 10 (2) की गणना करेगा। कंपाइलर को पता नहीं है कि log10 हर बार एक ही मान लौटाएगा। सभी संकलक के लिए, लॉग 10 (2) क्रमिक कॉल पर अलग-अलग मान लौटा सकता है।
अबेलेंकी

@abenkyky: ठीक है, मैं उसे वापस लेता हूं। चूंकि कंपाइलर कभी भी स्रोत को log()कार्यान्वयन के लिए नहीं देखता है इसलिए वह ऐसा नहीं करेगा। मेरी गलती।
जॉय

3
@abenky: चूंकि log10()सी मानक में एक फ़ंक्शन परिभाषित है, इसलिए संकलक इसे "विशेष रूप से" का इलाज करने के लिए स्वतंत्र है, जिसमें परिणाम को शामिल करना शामिल है, जो मुझे लगता है कि @ जोहान्स का सुझाव था?
कैफे

1
@CarlNorum: मैंने अभी-अभी जाँच की है, और log10(2)एक स्थिरांक के साथ 4.7 कम से कम प्रतिस्थापित करता है।
कैफ़े

8

यदि आप इसे तेजी से बनाना चाहते हैं, तो आप बिट ट्विडलिंग हैक्स (केवल पूर्णांक 2) में लुकअप टेबल का उपयोग कर सकते हैं ।

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];

इसके अलावा आप तरीकों builtin अपने compilers पर एक नज़र की तरह लेना चाहिए _BitScanReverseजो कर सकता है तेजी से हो, क्योंकि यह पूरी तरह से हार्डवेयर की गणना कर सकते हैं।

संभावित डुप्लिकेट पर भी एक नज़र डालें कि C ++ में पूर्णांक लॉग 2 () कैसे करें?


अंत में गुणा और तालिका क्यों दिखाई देती है? क्या आप सिर्फ (v + 1) ऐसा नहीं कर सकते थे जो दो की अगली शक्ति तक गोल हो जाए? और फिर, आप सही एक के बाद दौर नीचे के 2. अगले सत्ता में बदलाव कर सकता है
Safayet अहमद

@SafayetAhmed कृपया वर्णन करें कि आप उस पद्धति से किसी संख्या के लॉग 2 को कैसे खोजना चाहते हैं। मैं उस मूल्य को पाने का एक आसान तरीका नहीं जानता। लुकअप टेबल के साथ ऊपर के अंकगणित का उपयोग करने के अलावा, कोई गणना करने के लिए एक पुनरावृत्त / पुनरावर्ती एल्गोरिथ्म या समर्पित / अंतर्निहित हार्डवेयर का उपयोग कर सकता है।
bkausbk

32 बिट चर v के बिट्स को N (MSB) के माध्यम से 0 (LSB) गिना जाता है। कहें कि v का सबसे महत्वपूर्ण सेट बिट n है। क्या यह कहना सही होगा कि n मंजिल का प्रतिनिधित्व करता है (log2 (v))? क्या आपको अभी दिए गए v v को खोजने में कोई दिलचस्पी नहीं है?
सफायत अहमद

मुझे एहसास हुआ कि मैंने जो वर्णन किया है, वह आपको निकटतम 2 की न्यूनतम शक्ति देगा और वास्तविक लघुगणक नहीं। गुणन और तालिका लुकअप दो की शक्ति से लघुगणक तक जाने के लिए है। आप कुछ राशि द्वारा छोड़े गए नंबर 0x07C4ACDD को शिफ्ट कर रहे हैं। आपके द्वारा छोड़ी गई राशि दो की शक्ति पर निर्भर करेगी। संख्या ऐसी है, जिसमें 5 बिट्स का कोई भी लगातार क्रम अद्वितीय है। (0000 0111 1100 0100 0110 1100 1101 1101) आपको अनुक्रम (00000) (00001) ... (11101) देता है। कितनी दूर आपने शिफ्ट किया, इसके आधार पर आपको इन 5-बिट पैटर्नों में से एक मिलता है। फिर टेबल लुकअप। बहुत अच्छा।
सफायत अहमद

3
log2(x) = log10(x) / log10(2)

ओपी की दी गई जानकारी के आधार पर सरलता, स्पष्टता और कोड प्रदान करने के लिए अपवोट करें।
योयो

3
uint16_t log2(uint32_t n) {//but truncated
     if (n==0) throw ...
     uint16_t logValue = -1;
     while (n) {//
         logValue++;
         n >>= 1;
     }
     return logValue;
 }

मूल रूप से टॉमालॉजिक के समान ही है ।


1
इस समाधान में कुछ बातें गलत हैं, लेकिन सामान्य तौर पर, यह अच्छा है यदि आप फ्लोटिंग पॉइंट्स से बचना चाहते हैं। जब आप -1 के साथ अहस्ताक्षरित पूर्णांक को प्रारंभ कर रहे हैं, तो आप इसके लिए अतिप्रवाह पर भरोसा कर रहे हैं। इसे 0 पर प्रारंभ करके और फिर मान लौटाया जा सकता है - 1, यह मानकर कि आप 0 केस की जाँच करते हैं, जो आप करते हैं। दूसरा मुद्दा यह है कि जब आप n == 0 पर लूप स्टॉप पर निर्भर होते हैं, तो आपको स्पष्ट रूप से बताना चाहिए। इसके अलावा, यह बहुत अच्छा है अगर आप फ्लोटिंग पॉइंट्स से बचना चाहते हैं।
रियान क्विन

2

आपको math.h (C) या cmath (C ++) को शामिल करना होगा, इस बात का ध्यान रखें कि आपको उन गणित का अनुसरण करना होगा जो हम जानते हैं ... केवल संख्या> 0।

उदाहरण:

#include <iostream>
#include <cmath>
using namespace std;

int main(){
    cout<<log2(number);
}

2

मुझे और अधिक सटीकता की आवश्यकता थी कि बस सबसे महत्वपूर्ण बिट की स्थिति, और मेरे द्वारा उपयोग किए जा रहे माइक्रोकंट्रोलर में कोई गणित पुस्तकालय नहीं था। मैंने पाया कि सकारात्मक पूर्णांक मान तर्क के लिए 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 की गणना करने की आवश्यकता थी:

temp = (((uint32_t) N) * approx_log_base_2_N_times_256 / 512;

और सभी 16 बिट मान कभी भी 2% से अधिक नहीं थे


1

उपरोक्त सभी उत्तर सही हैं। नीचे दिए गए मेरा यह उत्तर मददगार हो सकता है अगर किसी को इसकी आवश्यकता हो। मैंने कई प्रश्नों में इस आवश्यकता को देखा है जिन्हें हम C का उपयोग करके हल कर रहे हैं।

log2 (x) = logy (x) / logy (2)

हालाँकि, यदि आप C भाषा का उपयोग कर रहे हैं और आप पूर्णांक में परिणाम चाहते हैं, तो आप निम्न का उपयोग कर सकते हैं:

int result = (int)(floor(log(x) / log(2))) + 1;

उम्मीद है की यह मदद करेगा।


0

अपने बुनियादी गणित पाठ्यक्रम से परामर्श करें log n / log 2। इससे कोई फर्क नहीं पड़ता कि आप चुनते हैं logया log10इस मामले में, logनए आधार द्वारा विभाजित करना चाल है।


0

उस्मान संगट ने जो किया, उसका बेहतर संस्करण

static inline uint64_t
log2(uint64_t n)
{
    uint64_t val;
    for (val = 0; n > 1; val++, n >>= 1);

    return val;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.