2008-08-29 29 views
5

del codice che arrotonda la divisione di dimostrare (C-sintassi):Come dividere due numeri a 64 bit nel kernel Linux?

#define SINT64 long long int 
#define SINT32 long int 

SINT64 divRound(SINT64 dividend, SINT64 divisor) 
{ 
    SINT32 quotient1 = dividend/divisor; 

    SINT32 modResult = dividend % divisor; 
    SINT32 multResult = modResult * 2; 
    SINT32 quotient2 = multResult/divisor; 

    SINT64 result = quotient1 + quotient2; 

    return (result); 
} 

Ora, se questo fosse l'utente-spazio che probabilmente non sarebbe nemmeno accorto che il nostro compilatore genera codice per gli operatori (ad esempio, divdi3() per divisione). È probabile che ci colleghiamo a "libgcc" senza neanche saperlo. Il problema è che Kernel-space è diverso (ad es. No libgcc). Cosa fare?

scansione di Google per un po ', si noti che tutti più o meno si rivolge la variante senza segno:

#define UINT64 long long int 
#define UINT32 long int 

UINT64 divRound(UINT64 dividend, UINT64 divisor) 
{ 
    UINT32 quotient1 = dividend/divisor; 

    UINT32 modResult = dividend % divisor; 
    UINT32 multResult = modResult * 2; 
    UINT32 quotient2 = multResult/divisor; 

    UINT64 result = quotient1 + quotient2; 

    return (result); 
} 

so come risolvere questo: override udivdi3() e umoddi3() con _do_div () _ da asm/div64.h. Fatto bene? Sbagliato. Firmato non è lo stesso di unsigned, sdivdi3() _ non chiama semplicemente udivdi3(), sono funzioni separate per un motivo.

Hai risolto questo problema? Conosci una biblioteca che mi aiuterà a fare questo? Sono davvero bloccato quindi qualsiasi cosa tu possa vedere qui, che proprio ora non sarebbe molto utile.

Grazie, Ciad

risposta

0

ldiv?

Modifica: rileggere il titolo, quindi si potrebbe voler ignorare questo. Oppure no, a seconda che abbia una versione non libreria appropriata.

4

Ecco la mia soluzione davvero ingenua. Il tuo chilometraggio può variare.

Mantieni un bit di segno, che è sign(dividend)^sign(divisor). (O *, o /, se si sta riporre il segno come 1 e -1, al contrario di falso e vero. In sostanza, negativo se uno dei due è negativo, positivo se nessuno o entrambi sono negativi.)

Poi , chiama la funzione di divisione senza segno sui valori assoluti di entrambi. Quindi aggiungi il segno al risultato.

P.S. Questo è il modo in cui è implementato in libgcc2.c (da GCC 4.2.3, la versione che è installata sul mio sistema Ubuntu). Ho appena controllato. :-)

0

Non credo che (almeno non riesce a trovare un modo per rendere) Chris' answer lavoro in questo caso perché do_div() cambia in realtà il dividendo sul posto. Ottenere il valore assoluto implica una variabile temporanea il cui valore cambierà il modo in cui richiedo ma non può essere passato dal mio __divdi3() override.

non vedo un modo per aggirare la firma dei parametri per valore di __divdi3() a questo punto se non per imitare la tecnica utilizzata da do_div().

Potrebbe sembrare che mi stia piegando all'indietro qui e dovrei solo creare un algoritmo per eseguire la divisione a 64 bit/32 bit di cui ho effettivamente bisogno. La complicazione aggiunta qui però è che ho un mucchio di codice numerico usando l'operatore '/' e dovrei passare attraverso quel codice e sostituire ogni '/' con le mie chiamate di funzione.

Sto diventando abbastanza disperato da fare proprio questo però.

Grazie per qualsiasi follow-up, Chad