Come verificare se un numero è una potenza di 2


585

Oggi avevo bisogno di un semplice algoritmo per verificare se un numero è una potenza di 2.

L'algoritmo deve essere:

  1. Semplice
  2. Corretto per qualsiasi ulongvalore.

Ho pensato a questo semplice algoritmo:

private bool IsPowerOfTwo(ulong number)
{
    if (number == 0)
        return false;

    for (ulong power = 1; power > 0; power = power << 1)
    {
        // This for loop used shifting for powers of 2, meaning
        // that the value will become 0 after the last shift
        // (from binary 1000...0000 to 0000...0000) then, the 'for'
        // loop will break out.

        if (power == number)
            return true;
        if (power > number)
            return false;
    }
    return false;
}

Ma poi ho pensato, che ne dici di verificare se è un numero esattamente rotondo? Ma quando ho controllato 2 ^ 63 + 1, sono tornato esattamente 63 a causa dell'arrotondamento. Quindi ho verificato se 2 alla potenza 63 è uguale al numero originale - e lo è, perché il calcolo viene eseguito in se non in numeri esatti:log2 xMath.Logdouble

private bool IsPowerOfTwo_2(ulong number)
{
    double log = Math.Log(number, 2);
    double pow = Math.Pow(2, Math.Round(log));
    return pow == number;
}

Questo è tornato trueper il dato valore errato: 9223372036854775809.

Esiste un algoritmo migliore?


1
Penso che la soluzione (x & (x - 1))possa restituire falsi positivi quando Xè una somma di poteri di due, ad es 8 + 16.
Joe Brown,

32
Tutti i numeri possono essere scritti come una somma di potenze di due, è per questo che possiamo rappresentare qualsiasi numero in binario. Inoltre, il tuo esempio non restituisce un falso positivo, perché 11000 e 10111 = 10000! = 0.
vlsd

1
@JoeBrown Non ha falsi positivi. In realtà l'espressione restituisce il più grande di qualsiasi somma di due poteri di due.
Samy Bencherif,

Risposte:


1220

C'è un semplice trucco per questo problema:

bool IsPowerOfTwo(ulong x)
{
    return (x & (x - 1)) == 0;
}

Nota, questa funzione segnalerà trueper 0, che non è un potere di 2. Se vuoi escluderlo, ecco come:

bool IsPowerOfTwo(ulong x)
{
    return (x != 0) && ((x & (x - 1)) == 0);
}

Spiegazione

Innanzitutto il binario bit per bit e l'operatore dalla definizione MSDN:

Binario e operatori sono predefiniti per i tipi integrali e bool. Per i tipi integrali, calcola l'AND bitonale logico dei suoi operandi. Per gli operandi bool, e calcola l'AND logico dei suoi operandi; cioè, il risultato è vero se e solo se entrambi i suoi operandi sono veri.

Ora diamo un'occhiata a come tutto ciò si svolge:

La funzione restituisce booleano (vero / falso) e accetta un parametro in ingresso di tipo unsigned long (x, in questo caso). Supponiamo per semplicità che qualcuno abbia superato il valore 4 e abbia chiamato la funzione in questo modo:

bool b = IsPowerOfTwo(4)

Ora sostituiamo ogni occorrenza di x con 4:

return (4 != 0) && ((4 & (4-1)) == 0);

Bene, sappiamo già che 4! = 0 passa a true, finora tutto bene. Ma per quanto riguarda:

((4 & (4-1)) == 0)

Questo si traduce ovviamente in questo:

((4 & 3) == 0)

Ma cos'è esattamente 4&3?

La rappresentazione binaria di 4 è 100 e la rappresentazione binaria di 3 è 011 (ricordare che & prende la rappresentazione binaria di questi numeri). Quindi abbiamo:

100 = 4
011 = 3

Immagina che questi valori siano impilati come un'aggiunta elementare. L' &operatore dice che se entrambi i valori sono uguali a 1, allora il risultato è 1, altrimenti è 0. Quindi 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0, e 0 & 1 = 0. Quindi facciamo la matematica:

100
011
----
000

Il risultato è semplicemente 0. Quindi torniamo indietro e guardiamo a ciò che la nostra dichiarazione di ritorno ora si traduce in:

return (4 != 0) && ((4 & 3) == 0);

Che si traduce ora in:

return true && (0 == 0);
return true && true;

Sappiamo tutti che true && trueè semplicemente truee questo dimostra che per il nostro esempio 4 è una potenza di 2.


56
@Kripp: il numero sarà in forma binaria 1000 ... 000. Quando lo -1, sarà nel formato 0111 ... 111. Pertanto, il numero binario dei due numeri comporterebbe 000000. Ciò non accadrebbe per i non-power-of-twos, poiché 1010100 per esempio diventerebbe 1010011, risultando in un (continua ...)
configuratore

47
... Il risultato è un 1010000 dopo il binario e. L'unico falso positivo sarebbe 0, motivo per cui dovrei usare: return (x! = 0) && ((x & (x - 1)) == 0);
configuratore

6
Kripp, considera (2: 1, 10: 1) (4: 3, 100: 11) (8: 7, 1000: 111) (16:15, 10000: 1111) Vedi lo schema?
Thomas L Holaday,

13
@ShuggyCoUk: il complemento a due è come sono rappresentati i numeri negativi. Poiché si tratta di un numero intero senza segno, la rappresentazione di numeri negativi non è rilevante. Questa tecnica si basa solo sulla rappresentazione binaria di numeri interi non negativi.
Greg Hewgill

4
@SoapBox - cosa c'è di più comune? Zero o numeri diversi da zero che non sono potenze di due? Questa è una domanda a cui non puoi rispondere senza un altro contesto. E davvero, davvero non importa comunque.
configuratore

97

Alcuni siti che documentano e spiegano questo e altri hack di manipolazione sono:

E il nonno di loro, il libro "Hacker's Delight" di Henry Warren, Jr .:

Come spiega la pagina di Sean Anderson , l'espressione ((x & (x - 1)) == 0)indica erroneamente che 0 è una potenza di 2. Suggerisce di usare:

(!(x & (x - 1)) && x)

per correggere quel problema.


4
0 è una potenza di 2 ... 2 ^ -inf = 0.;););)
Michael Bray,

4
Poiché si tratta di un thread con tag C # , vale la pena sottolineare che l'ultima espressione (di Sean Anderson) è illegale in C # poiché !può essere applicata solo a tipi booleani e &&richiede inoltre che entrambi gli operandi siano booleani (tranne che gli operatori definiti dall'utente rendere possibili altre cose, ma questo non è rilevante per ulong.)
Jeppe Stig Nielsen

40

return (i & -i) == i


2
qualche suggerimento sul perché questo funzionerà o meno? ho verificato la sua correttezza solo in Java, dove ci sono solo ints / long firmati. se è corretto, questa sarebbe la risposta superiore. più veloce + più piccolo
Andreas Petersson,

7
Sfrutta una delle proprietà della notazione del complemento a due: per calcolare il valore negativo di un numero si esegue una negazione bit a bit e si aggiunge 1 al risultato. iVerrà impostato anche il bit meno significativo impostato -i. I bit sottostanti saranno 0 (in entrambi i valori) mentre i bit sopra saranno invertiti l'uno rispetto all'altro. Il valore di i & -isarà quindi il bit set meno significativo in i(che è una potenza di due). Se iha lo stesso valore, quello era l'unico bit impostato. Non riesce quando iè 0 per lo stesso motivo i & (i - 1) == 0.
Michael Carman,

6
Se iè un tipo senza segno, il complemento a due non ha nulla a che fare con esso. Stai semplicemente sfruttando le proprietà dell'aritmetica modulare e bit a bit e.
R .. GitHub FERMA AIUTANDO ICE

2
Questo non funziona se i==0(restituisce (0&0==0)che è true). Dovrebbe esserereturn i && ( (i&-i)==i )
bobobobo il

22
bool IsPowerOfTwo(ulong x)
{
    return x > 0 && (x & (x - 1)) == 0;
}

3
Questa soluzione è migliore perché può anche gestire il numero negativo se il negativo può passare. (Se lungo anziché ulong)
Steven

Perché in questo caso un decimale passa come potenza di due?
chris Frisina,


17

Ecco una semplice soluzione C ++ :

bool IsPowerOfTwo( unsigned int i )
{
    return std::bitset<32>(i).count() == 1;
}

8
su gcc questo si compila in un singolo builtin gcc chiamato __builtin_popcount. Sfortunatamente, una famiglia di processori non ha ancora una singola istruzione di assemblaggio per farlo (x86), quindi è il metodo più veloce per il conteggio dei bit. Su qualsiasi altra architettura questa è una singola istruzione di assemblaggio.
deft_code

3
@deft_code supporto per microarchitettura x86 più recentepopcnt
phuclv

13

Il seguente addendum alla risposta accettata può essere utile per alcune persone:

Una potenza di due, quando espressa in binario, apparirà sempre come 1 seguita da n zero dove n è maggiore o uguale a 0. Es:

Decimal  Binary
1        1     (1 followed by 0 zero)
2        10    (1 followed by 1 zero)
4        100   (1 followed by 2 zeroes)
8        1000  (1 followed by 3 zeroes)
.        .
.        .
.        .

e così via.

Quando sottraggiamo 1da questo tipo di numeri, diventano 0 seguiti da n e di nuovo n è uguale a quello sopra. Ex:

Decimal    Binary
1 - 1 = 0  0    (0 followed by 0 one)
2 - 1 = 1  01   (0 followed by 1 one)
4 - 1 = 3  011  (0 followed by 2 ones)
8 - 1 = 7  0111 (0 followed by 3 ones)
.          .
.          .
.          .

e così via.

Venendo al nocciolo

Cosa succede quando facciamo un AND bit a bit di un numero x, che è una potenza di 2, e x - 1?

Quello di xviene allineato con lo zero di x - 1e tutti gli zero di xvengono allineati con quelli di x - 1, facendo sì che AND bit a bit si traduca in 0. Ed è così che la risposta a riga singola sopra menzionata è corretta.


Ulteriore aggiunta alla bellezza della risposta accettata sopra -

Quindi, abbiamo una proprietà a nostra disposizione ora:

Quando sottraggiamo 1 da qualsiasi numero, nella rappresentazione binaria il 1 più a destra diventerà 0 e tutti gli zero prima di quel 1 più a destra diventeranno 1

Un uso straordinario di questa proprietà è scoprire: quanti 1 sono presenti nella rappresentazione binaria di un determinato numero? Il codice breve e dolce per farlo per un dato intero xè:

byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);

Un altro aspetto dei numeri che può essere provato dal concetto spiegato sopra è "Può ogni numero positivo essere rappresentato come la somma dei poteri di 2?".

Sì, ogni numero positivo può essere rappresentato come la somma dei poteri di 2. Per qualsiasi numero, prendi la sua rappresentazione binaria. Es: Prendi il numero 117.

The binary representation of 117 is 1110101

Because  1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have  117     = 64      + 32     + 16    + 0    + 4   + 0  + 1

@Michi: Ho affermato da qualche parte che 0 è un numero positivo? O una potenza di 2?
displayName

Sì, mettendo lo 0 come esempio e facendo quella matematica su quella rappresentazione binaria. Crea una confusione.
Michi,

1
Se l'aggiunta di due numeri ti confonde nel credere che debbano essere positivi, non posso farci nulla. Inoltre, nella rappresentazione è stato mostrato 0 per indicare che quella potenza di 2 è saltata in questo numero. Chiunque conosca la matematica di base è consapevole che aggiungere 0 significa non aggiungere nulla.
displayName

10

Dopo aver pubblicato la domanda ho pensato alla seguente soluzione:

Dobbiamo verificare se esattamente una delle cifre binarie è una. Quindi spostiamo semplicemente il numero a destra di una cifra alla volta e ritorniamo truese è uguale a 1. Se in qualsiasi momento arriviamo a un numero dispari ( (number & 1) == 1), sappiamo che il risultato è false. Ciò si è rivelato (utilizzando un benchmark) leggermente più veloce del metodo originale per valori (grandi) reali e molto più veloce per valori falsi o piccoli.

private static bool IsPowerOfTwo(ulong number)
{
    while (number != 0)
    {
        if (number == 1)
            return true;

        if ((number & 1) == 1)
            // number is an odd number and not 1 - so it's not a power of two.
            return false;

        number = number >> 1;
    }
    return false;
}

Certo, la soluzione di Greg è molto meglio.


10
    bool IsPowerOfTwo(int n)
    {
        if (n > 1)
        {
            while (n%2 == 0)
            {
                n >>= 1;
            }
        }
        return n == 1;
    }

Ed ecco un algoritmo generale per scoprire se un numero è una potenza di un altro numero.

    bool IsPowerOf(int n,int b)
    {
        if (n > 1)
        {
            while (n % b == 0)
            {
                n /= b;
            }
        }
        return n == 1;
    }

6
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;

1
È questo c#? Immagino c++che xsia tornato come un bool.
Mariano Desanze,

1
L'ho scritto come C ++. Per renderlo C # è banale: bool isPow2 = ((x & ~ (x-1)) == x)? x! = 0: false;
abelenky,

4

Scopri se il numero dato è una potenza di 2.

#include <math.h>

int main(void)
{
    int n,logval,powval;
    printf("Enter a number to find whether it is s power of 2\n");
    scanf("%d",&n);
    logval=log(n)/log(2);
    powval=pow(2,logval);

    if(powval==n)
        printf("The number is a power of 2");
    else
        printf("The number is not a power of 2");

    getch();
    return 0;
}

Oppure, in C #: return x == Math.Pow (2, Math.Log (x, 2));
configuratore

4
Rotto. Soffre di importanti problemi di arrotondamento in virgola mobile. Usa cose frexppiuttosto che cattive logse vuoi usare il virgola mobile.
R .. GitHub FERMA AIUTANDO ICE

4
bool isPowerOfTwo(int x_)
{
  register int bitpos, bitpos2;
  asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_));
  asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_));
  return bitpos > 0 && bitpos == bitpos2;
}

4
int isPowerOfTwo(unsigned int x)
{
    return ((x != 0) && ((x & (~x + 1)) == x));
}

Questo è veramente veloce. Sono necessari circa 6 minuti e 43 secondi per controllare tutti i 2 ^ 32 numeri interi.


4
return ((x != 0) && !(x & (x - 1)));

Se xè una potenza di due, il suo solo 1 bit è in posizione n. Questo significa che x – 1ha uno 0 in posizione n. Per capire perché, ricorda come funziona una sottrazione binaria. Sottraendo 1 da x, il prestito si propaga fino alla posizione n; il bit ndiventa 0 e tutti i bit inferiori diventano 1. Ora, poiché xnon ha 1 bit in comune con x – 1, x & (x – 1)è 0 ed !(x & (x – 1))è vero.


3

Un numero è una potenza di 2 se contiene solo 1 bit impostato. Possiamo usare questa proprietà e la funzione genericacountSetBits per scoprire se un numero ha una potenza di 2 o meno.

Questo è un programma C ++:

int countSetBits(int n)
{
        int c = 0;
        while(n)
        {
                c += 1;
                n  = n & (n-1);
        }
        return c;
}

bool isPowerOfTwo(int n)
{        
        return (countSetBits(n)==1);
}
int main()
{
    int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
    for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
        printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
    return 0;
}

Non è necessario verificare esplicitamente che 0 sia una Potenza di 2, poiché restituisce False anche per 0.

PRODUZIONE

Num:0   Set Bits:0   is power of two: 0
Num:1   Set Bits:1   is power of two: 1
Num:2   Set Bits:1   is power of two: 1
Num:3   Set Bits:2   is power of two: 0
Num:4   Set Bits:1   is power of two: 1
Num:5   Set Bits:2   is power of two: 0
Num:15  Set Bits:4   is power of two: 0
Num:16  Set Bits:1   is power of two: 1
Num:22  Set Bits:3   is power of two: 0
Num:32  Set Bits:1   is power of two: 1
Num:38  Set Bits:3   is power of two: 0
Num:64  Set Bits:1   is power of two: 1
Num:70  Set Bits:3   is power of two: 0

restituendo c come 'int' quando la funzione ha un tipo di ritorno 'ulong'? Usando un whileinvece di un if? Personalmente non riesco a vedere un motivo, ma sembrerebbe funzionare. EDIT: - no ... restituirà 1 per qualcosa di più grande di 0!?
James Khoury,

@JamesKhoury Stavo scrivendo un programma c ++ quindi ho restituito erroneamente un int. Comunque quello era un piccolo refuso e non meritava un downvote. Ma non riesco a capire il ragionamento per il resto del tuo commento "usando while invece di if" e "restituirà 1 per qualcosa di più grande di 0". Ho aggiunto lo stub principale per controllare l'output. AFAIK è l'output previsto. Correggimi se sbaglio.
jerrymouse,

3

Ecco un altro metodo che ho ideato, in questo caso usando |invece di &:

bool is_power_of_2(ulong x) {
    if(x ==  (1 << (sizeof(ulong)*8 -1) ) return true;
    return (x > 0) && (x<<1 == (x|(x-1)) +1));
}

Ti serve un (x > 0)po 'qui?
configuratore

@configurator, sì, altrimenti is_power_of_2 (0) restituisce true
Chethan,

3

per qualsiasi potenza di 2, vale anche quanto segue.

n & (- n) == n

NOTA: non riesce per n = 0, quindi è necessario verificarlo.
Motivo per cui funziona:
-n è il complemento 2s di n. -n avrà ogni bit a sinistra del bit più a destra impostato di n capovolto rispetto a n. Per potenze di 2 c'è solo un bit impostato.


2

Esempio

0000 0001    Yes
0001 0001    No

Algoritmo

  1. Utilizzando una maschera di bit, dividere NUMla variabile in binario

  2. IF R > 0 AND L > 0: Return FALSE

  3. Altrimenti, NUMdiventa quello diverso da zero

  4. IF NUM = 1: Return TRUE

  5. Altrimenti, vai al passaggio 1

Complessità

Tempo ~ O(log(d))dove dè il numero di cifre binarie


1

Miglioramento della risposta di @ user134548, senza aritmetica dei bit:

public static bool IsPowerOfTwo(ulong n)
{
    if (n % 2 != 0) return false;  // is odd (can't be power of 2)

    double exp = Math.Log(n, 2);
    if (exp != Math.Floor(exp)) return false;  // if exp is not integer, n can't be power
    return Math.Pow(2, exp) == n;
}

Questo funziona bene per:

IsPowerOfTwo(9223372036854775809)

le operazioni in virgola mobile sono molto più lente di una semplice espressione bit a bit
phuclv

1

Mark gravell ha suggerito questo se si dispone di .NET Core 3, System.Runtime.Intrinsics.X86.Popcnt.PopCount

public bool IsPowerOfTwo(uint i)
{
    return Popcnt.PopCount(i) == 1
}

Singola istruzione, più veloce (x != 0) && ((x & (x - 1)) == 0)ma meno portatile.


sei sicuro che sia più veloce di (x != 0) && ((x & (x - 1)) == 0)? Ne dubito, esp. su sistemi più vecchi in cui popcnt non è disponibile
phuclv,

Non è più veloce Ho appena provato questo su una moderna CPU Intel e verificato POPCNT in uso nello smontaggio (garantito, in codice C, non .NET). POPCNT è più veloce per il conteggio dei bit in generale, ma nel caso single-bit-on il trucco del twiddling dei bit è ancora più veloce del 10%.
Eraoul,

Oops, lo riprendo. Stavo testando in un ciclo dove penso che la predizione del ramo fosse "barare". POPCNT è in effetti una singola istruzione che viene eseguita in un singolo ciclo di clock ed è più veloce se disponibile.
Eraoul

0

In C, ho testato il i && !(i & (i - 1)trucco e confrontato con__builtin_popcount(i) , usando gcc su Linux, con il flag -mpopcnt per essere sicuro di usare l'istruzione POPCNT della CPU. Il mio programma di test ha contato il numero di numeri interi tra 0 e 2 ^ 31 che erano una potenza di due.

All'inizio ho pensato che i && !(i & (i - 1)fosse il 10% più veloce, anche se ho verificato che POPCNT è stato utilizzato nello smontaggio in cui ho usato__builtin_popcount .

Tuttavia, mi sono reso conto di aver incluso un'istruzione if e la previsione del ramo probabilmente stava andando meglio sulla versione a punte di bit. Ho rimosso if e POPCNT è finito più velocemente, come previsto.

risultati:

CPU Intel (R) Core (TM) i7-4771 max 3,90 GHz

Timing (i & !(i & (i - 1))) trick
30

real    0m13.804s
user    0m13.799s
sys     0m0.000s

Timing POPCNT
30

real    0m11.916s
user    0m11.916s
sys     0m0.000s

Processore AMD Ryzen Threadripper 2950X 16 core max 3,50 GHz

Timing (i && !(i & (i - 1))) trick
30

real    0m13.675s
user    0m13.673s
sys 0m0.000s

Timing POPCNT
30

real    0m13.156s
user    0m13.153s
sys 0m0.000s

Si noti che qui la CPU Intel sembra leggermente più lenta di AMD con il bit twiddling, ma ha un POPCNT molto più veloce; AMD POPCNT non fornisce un grande impulso.

popcnt_test.c:

#include "stdio.h"

// Count # of integers that are powers of 2 up to 2^31;
int main() {
  int n;
  for (int z = 0; z < 20; z++){
      n = 0;
      for (unsigned long i = 0; i < 1<<30; i++) {
       #ifdef USE_POPCNT
        n += (__builtin_popcount(i)==1); // Was: if (__builtin_popcount(i) == 1) n++;
       #else
        n += (i && !(i & (i - 1)));  // Was: if (i && !(i & (i - 1))) n++;
       #endif
      }
  }

  printf("%d\n", n);
  return 0;
}

Esegui test:

gcc popcnt_test.c -O3 -o test.exe
gcc popcnt_test.c -O3 -DUSE_POPCNT -mpopcnt -o test-popcnt.exe

echo "Timing (i && !(i & (i - 1))) trick"
time ./test.exe

echo
echo "Timing POPCNT"
time ./test-opt.exe

0

Vedo che molte risposte suggeriscono di restituire n &&! (N & (n - 1)) ma alla mia esperienza se i valori di input sono negativi restituisce valori falsi. Condividerò qui un altro approccio semplice poiché sappiamo che una potenza di due numeri ha solo un bit impostato, quindi semplicemente conteremo il numero di bit impostato che richiederà tempo O (log N).

while (n > 0) {
    int count = 0;
    n = n & (n - 1);
    count++;
}
return count == 1;

Controlla questo articolo per contare no. di bit impostati


-1
private static bool IsPowerOfTwo(ulong x)
{
    var l = Math.Log(x, 2);
    return (l == Math.Floor(l));
}

Provalo per il numero 9223372036854775809. Funziona? Penserei di no, a causa di errori di arrotondamento.
configuratore

1
@configurator 922337203685477580_9_ non mi sembra una potenza di 2;)
Kirschstein

1
@Kirschstein: quel numero gli ha dato un falso positivo.
Erich Mirabal,

7
Kirschstein: Neanche a me sembra simile. Sembra che sia simile alla funzione ...
Configuratore

-2

Questo programma in java restituisce "vero" se il numero è una potenza di 2 e restituisce "falso" se non è una potenza di 2

// To check if the given number is power of 2

import java.util.Scanner;

public class PowerOfTwo {
    int n;
    void solve() {
        while(true) {
//          To eleminate the odd numbers
            if((n%2)!= 0){
                System.out.println("false");
                break;
            }
//  Tracing the number back till 2
            n = n/2;
//  2/2 gives one so condition should be 1
            if(n == 1) {
                System.out.println("true");
                break;
            }
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        PowerOfTwo obj = new PowerOfTwo();
        obj.n = in.nextInt();
        obj.solve();
    }

}

OUTPUT : 
34
false

16
true

1
questa domanda è taggata C # e anche la tua soluzione è molto lenta rispetto alle soluzioni precedenti [
phuclv
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.