Questo numero ha una potenza esatta di -2: (Molto) Modalità Difficile


26

Questa è una versione della recente sfida Questo numero è un potere intero di -2? con una serie diversa di criteri progettati per evidenziare la natura interessante del problema e rendere la sfida più difficile. Ho preso in considerazione qui .

La sfida, meravigliosamente dichiarata da Toby nella domanda collegata, è:

Esistono modi intelligenti per determinare se un numero intero è una potenza esatta di 2. Questo non è più un problema interessante, quindi determiniamo se un dato numero intero è una potenza esatta di -2 . Per esempio:

-2 => yes: (-2)¹
-1 => no
0 => no
1 => yes: (-2)⁰
2 => no
3 => no
4 => yes: (-2)²

Regole:

  • Un numero intero è 64 bit, firmato, complemento a due. Questo è l' unico tipo di dati con cui puoi lavorare.
  • È possibile utilizzare solo le seguenti operazioni. Ognuno di questi conta come un'operazione.
    • n << k, n >> k: Spostamento sinistro / destro ndi kbit. Il bit di segno viene esteso con lo spostamento a destra.
    • n >>> k: Spostamento a destra ma non estendere il bit di segno. Gli 0 vengono spostati.
    • a & b, a | b, a ^ b: Bitwise AND, OR, XOR.
    • a + b, a - b, a * b: Aggiungere, sottrarre, moltiplicare.
    • ~b: Inverti bit a bit.
    • -b: Negazione del complemento a due.
    • a / b, a % b: Divide (quoziente intero, arrotondamenti verso 0) e modulo.
      • Modulo di numeri negativi utilizza le regole specificate in C99 : (a/b) * b + a%bdeve essere uguale a. Così 5 % -3è 2ed -5 % 3è -2:
      • 5 / 3è 1, 5 % 3è 2, come 1 * 3 + 2 = 5.
      • -5 / 3è -1, -5 % 3è -2, come -1 * 3 + -2 = -5.
      • 5 / -3è -1, 5 % -3è 2, come -1 * -3 + 2 = 5.
      • -5 / -3è 1, -5 % -3è -2, come 1 * -3 + -2 = -5.
      • Notare che qui l' //operatore di divisione del pavimento di Python non soddisfa la proprietà di "arrotondamento verso 0" della divisione e che anche l' %operatore di Python non soddisfa i requisiti.
    • Le assegnazioni non contano come un'operazione. Come in C, le assegnazioni valutano il valore del lato sinistro dopo l'assegnazione: a = (b = a + 5)imposta bsu a + 5, quindi imposta asu be conta come un'operazione.
    • Le assegnazioni composte possono essere usate come a += bmezzi a = a + be contano come un'unica operazione.
  • Puoi usare costanti intere, non contano come nulla.
  • Le parentesi per specificare l'ordine delle operazioni sono accettabili.
  • È possibile dichiarare funzioni. Le dichiarazioni di funzioni possono essere in qualsiasi stile conveniente per te, ma tieni presente che gli interi a 64 bit sono l' unico tipo di dati valido. Le dichiarazioni di funzione non contano come operazioni, ma una chiamata di funzione conta come una. Inoltre, per essere chiari: le funzioni possono contenere più returnistruzioni e returnsono consentite da qualsiasi punto. Ilreturn stesso non conta come un'operazione.
  • È possibile dichiarare le variabili gratuitamente.
  • È possibile utilizzare i whileloop, ma non è possibile utilizzare ifo for. Gli operatori utilizzati nella whilecondizione contano per il tuo punteggio. whilei loop vengono eseguiti fintanto che la loro condizione restituisce un valore diverso da zero (uno 0 "veritiero" in lingue che hanno questo concetto non è un risultato valido). Dall'inizio del ritorno è consentito, si è permesso di usare breakpure
  • Overflow / underflow è consentito e non verrà eseguito alcun blocco del valore. Viene trattato come se l'operazione fosse effettivamente avvenuta correttamente e quindi veniva troncata a 64 bit.

Punteggio / criteri vincenti:

Il tuo codice deve produrre un valore diverso da zero se l'ingresso è una potenza di -2 e zero altrimenti.

Questo è il . Il punteggio è il numero totale di operazioni presenti nel codice (come definito sopra), non il numero totale di operazioni eseguite in fase di esecuzione. Il seguente codice:

function example (a, b) {
    return a + ~b;
}

function ispowerofnegtwo (input) {
    y = example(input, 9);
    y = example(y, 42);
    y = example(y, 98);
    return y;
}

Contiene 5 operazioni: due nella funzione e tre chiamate di funzione.

Non importa come si presenta il risultato, si utilizza qualsiasi cosa sia conveniente nella propria lingua, sia che si tratti in definitiva di archiviare il risultato in una variabile, restituendolo da una funzione o altro.

Il vincitore è il post che è dimostrabilmente corretto (fornire una prova casuale o formale se necessario) e ha il punteggio più basso come descritto sopra.

Bonus Sfida in modalità molto difficile!

Per avere la possibilità di vincere assolutamente nulla, tranne la potenziale capacità di impressionare le persone alle feste, inviare una risposta senza usare whileloop! Se ne vengono presentate abbastanza, potrei anche considerare di dividere i gruppi vincitori in due categorie (con e senza loop).


Nota: se si desidera fornire una soluzione in una lingua che supporta solo numeri interi a 32 bit, è possibile farlo, purché si giustifichi sufficientemente che sarà comunque corretta per i numeri interi a 64 bit in una spiegazione.

Inoltre: alcune funzionalità specifiche della lingua possono essere consentite gratuitamente se non eludono le regole ma sono necessarie per costringere la tua lingua a comportarsi secondo le regole di cui sopra . Ad esempio (inventato), permetterò un confronto libero non uguale a 0 nei whilecicli, se applicato alla condizione nel suo insieme, come soluzione alternativa per un linguaggio che ha "verità" 0. Non sono consentiti chiari tentativi di trarre vantaggio da questi tipi di cose - ad esempio, il concetto di "verità" 0 o di valori "non definiti" non esiste nel set di regole di cui sopra e pertanto non è possibile fare affidamento su di essi.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Dennis,

@hvd Se leggi questo: dovresti ripristinare completamente la tua risposta! Supponendo che sia corretto, anche senza m ^= s che sia ancora impressionante, e penso che sarebbe del tutto OK fare la sostituzione per migliorarla ancora di più.
Jason C

Come ha senso permettere whilee breakma no if? if (x) { ... }è equivalente a while (x) { ... break; }.
R ..

@R .. Non ha senso al 100% ( breake i primi ritorni sono la parte spiacevole) ed è una lunga storia e una lezione appresa nelle regole per le sfide future. C'è sempre la versione "bonus"! :)
Jason C

1
Perché ife fornon sono consentiti? int x=condition; while (x) { ... x=0; }è gratuito, solo più codice. Stessa cosa con lo stile c for.
Qwertiy,

Risposte:


35

C ++, 15 operazioni

Non ho idea del perché while loop siano consentiti mentre distruggono l'intera sfida. Ecco una risposta senza nessuna:

int64_t is_negpow2(int64_t n) {
    int64_t neg = uint64_t(n) >> 63; // n >>> 63
    n = (n ^ -neg) + neg; // if (n < 0) n = -n;
    int64_t evenbits = n & int64_t(0xaaaaaaaaaaaaaaaaull >> neg);
    int64_t n1 = n - 1;
    int64_t pot = n & n1;
    int64_t r = pot | (n1 >> 63) | evenbits;
    return ~((r | -r) >> 63); // !r
}

Perché i whileloop distruggono l'intera sfida ?
Mr. Xcoder,

10
@ Mr.Xcoder Perché la sfida è di farlo con semplici operazioni bit per bit e whileva contro questo in ogni modo.
orlp,

Voglio dire, a meno che non si facciano dei cicli while moltiplicando il numero di operazioni per il numero di volte eseguito nel ciclo per uno statico no qualcosa del genere.
Magic Octopus Urn,

Ho fatto un commento al riguardo qui .
Jason C,

@JasonC Questo perché avrei dovuto usare un turno giusto senza bit di segno. Ho modificato il codice (lo utilizza uint64_tperché è l'unico modo per ottenere il turno giusto senza l'estensione del segno.)
Orlp

25

Python 2 , 3 operazioni

def f(n):
 while n>>1:
  while n&1:return 0
  n=n/-2
 return n

Provalo online!

Le operazioni sono >> , &, /.

L'idea è quella di dividere ripetutamente per -2. Poteri del -2 a catena fino a 1: -8 -> 4 -> -2 -> 1. Se colpiamo a1 , accetta. Se colpiamo un numero dispari prima di colpire 1, respingi. Dobbiamo anche rifiutare 0, che va per sempre a se stesso.

Il while n>>1:loop fino a quando nè 0 o 1. Quando il loop si interrompe, nviene restituito se stesso, ed 1è un output Truthy e 0uno Falsey. All'interno del loop, rifiutiamo ripetutamente di applicare n -> n/-2e rifiutiamo qualsiasi dispari n.

Dal momento che /viene utilizzato solo su valori pari, il suo comportamento di arrotondamento non entra mai in gioco. Quindi, non importa che Python arrotonda diversamente dalle specifiche.


Bello. Logica intelligente nell'algoritmo e buon lavoro che combina i condizionali in operazioni a bit. Inoltre, posso confermare, l'implementazione funziona in C.
Jason C

Perché while n&1invece di if n&1?
Mark Ransom,

2
@MarkRansom La sfida non consente if.
xnor

Ah, l'ho perso. Sostituzione molto intelligente.
Mark Ransom,

1
@EvSunWoodard Il punteggio è il numero di operatori nel codice, non il numero di chiamate a loro durante l'esecuzione, che dipende dall'input: "Questo è il codice atomico-golf. Il tuo punteggio è il numero totale di operazioni presenti nel tuo codice ".
xnor

11

Ruggine, 14 12 operazioni (nessun loop)

Richiede l'ottimizzazione ( -O) o -C overflow-checks=noper abilitare la sottrazione traboccante invece del panico.

fn is_power_of_negative_2(input: i64) -> i64 {
    let sign = input >> 63;
    // 1 op
    let abs_input = (input ^ sign) - sign;
    // 2 ops
    let bad_power_of_two = sign ^ -0x5555_5555_5555_5556; // == 0xaaaa_aaaa_aaaa_aaaa
    // 1 op
    let is_not_power_of_n2 = abs_input & ((abs_input - 1) | bad_power_of_two);
    // 3 ops 
    let is_not_power_of_n2 = (is_not_power_of_n2 | -is_not_power_of_n2) >> 63;
    // 3 ops 
    input & !is_not_power_of_n2
    // 2 ops
}

(Per chiarire: non !xè bitwise- qui, non logico-NOT)

Casi test:

#[test]
fn test_is_power_of_negative_2() {
    let mut value = 1;
    for _ in 0 .. 64 {
        assert_ne!(0, is_power_of_negative_2(value), "wrong: {} should return nonzero", value);
        value *= -2;
    }
}

#[test]
fn test_not_power_of_negative_2() {
    for i in &[0, -1, 2, 3, -3, -4, 5, -5, 6, -6, 7, -7, 8, 1<<61, -1<<62, 2554790084739629493, -4676986601000636537] {
        assert_eq!(0, is_power_of_negative_2(*i), "wrong: {} should return zero", i);
    }
}

Provalo online!


L'idea è di verificare se | x | è una potenza di 2 (usando (y & (y - 1)) == 0come al solito). Se x è una potenza di 2, allora controlliamo ulteriormente (1) quando x >= 0, dovrebbe anche essere una potenza pari a 2, o (2) quando x < 0, dovrebbe essere una potenza dispari di 2. Controlliamo questo facendo &il " bad_power_of_two"maschera 0x ... aaaa quando x >= 0(produce 0 solo quando è una potenza pari), o 0x ... 5555 quando x < 0.


Ho rubato il tuo ~((r | -r) >> 63)trucco per finire di sistemare la mia risposta.
orlp,

6

Haskell, 2 3 operazioni

import Data.Bits (.&.)

f 0 = False
f 1 = True
f n | n .&. 1 == 0 = f (n `div` -2)
f n | otherwise    = False

Definisce una funzione ricorsiva f(n). Le operazioni utilizzate sono la funzione call ( f), division ( div) e bitwise e ( .&.).

Non contiene loop a causa del fatto che Haskell non ha istruzioni loop :-)


4
Perché non mi sorprende che la soluzione Haskell che non utilizza loop sia fornita da qualcuno chiamato "Opportunista?" =)
Cort Ammon - Ripristina Monica il

1
Sono molto titubante circa il f 0, f 1, f n ...ecco perché sono essenzialmente if's in incognito, anche se poi di nuovo, ho permesso while+ breake l'inizio returns, quindi mi sembra giusto. Mentre sembra trarre vantaggio dal fatto che il mio set di regole venga inavvertitamente lasciato aperto all'interpretazione, è una buona soluzione.
Jason C

3
In particolare le |s sono particolarmente in alto nell'aria. Detto questo, ciò viola una determinata regola in modo meno discutibile: il confronto ==non è consentito. Si noti, tuttavia, che se la mia interpretazione di questo codice è corretto, l'utilizzo di booleani qui non appare accettabile come sostituendo valori interi arbitrari al loro posto non sembra cambiare i risultati, e sono più di una forma presentazione finale.
Jason C

@JasonC Sto solo usato ==perché non c'è altro modo di cast Inta Boolo "Truthy" in Haskell. Se la corrispondenza del modello e le protezioni violano la ifregola "no s" è la tua chiamata ;-)
Opportunista

18
Con la corrispondenza dei modelli, è possibile semplicemente codificare i risultati per tutti i numeri interi a 64 bit utilizzando 0 operazioni.
xnor

5

Python 3, 10 o 11 9 operazioni

def g(x):
 while x:
  while 1 - (1 + ~int(x - -2 * int(float(x) / -2))) & 1: x /= -2
  break
 while int(1-x):
     return 0
 return 5  # or any other value

Restituisce 5per poteri di -2, 0altrimenti


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Dennis,

5

C, 5 operazioni

long long f(long long x){
    x=x ^ ((x & 0xaaaaaaaaaaaaaaaa) * 6);
    while(x){
        while(x&(x-1))
            return 0;
        return 1;
    }
    return 0;
}

C, 10 operazioni, senza anelli

long long f(long long x){
    x = x ^ ((x & 0xaaaaaaaaaaaaaaaa) * 6);
    long long t = x & (x-1);
    return (((t-1) & ~t) >> 63) * x;
}

C, 1 operazione

long long f(long long x){
    long long a0=1, a1=-2, a2=4, a3=-8, a4=16, a5=-32, a6=64, a7=-128, a8=256, a9=-512, a10=1024, a11=-2048, a12=4096, a13=-8192, a14=16384, a15=-32768, a16=65536, a17=-131072, a18=262144, a19=-524288, a20=1048576, a21=-2097152, a22=4194304, a23=-8388608, a24=16777216, a25=-33554432, a26=67108864, a27=-134217728, a28=268435456, a29=-536870912, a30=1073741824, a31=-2147483648, a32=4294967296, a33=-8589934592, a34=17179869184, a35=-34359738368, a36=68719476736, a37=-137438953472, a38=274877906944, a39=-549755813888, a40=1099511627776, a41=-2199023255552, a42=4398046511104, a43=-8796093022208, a44=17592186044416, a45=-35184372088832, a46=70368744177664, a47=-140737488355328, a48=281474976710656, a49=-562949953421312, a50=1125899906842624, a51=-2251799813685248, a52=4503599627370496, a53=-9007199254740992, a54=18014398509481984, a55=-36028797018963968, a56=72057594037927936, a57=-144115188075855872, a58=288230376151711744, a59=-576460752303423488, a60=1152921504606846976, a61=-2305843009213693952, a62=4611686018427387904, a63=-9223372036854775807-1, a64=0;
    while(a0){
        long long t = x ^ a0;
        long long f = 1;
        while(t){
            f = 0;
            t = 0;
        }
        while(f)
            return 1;
        a0=a1; a1=a2; a2=a3; a3=a4; a4=a5; a5=a6; a6=a7; a7=a8; a8=a9; a9=a10; a10=a11; a11=a12; a12=a13; a13=a14; a14=a15; a15=a16; a16=a17; a17=a18; a18=a19; a19=a20; a20=a21; a21=a22; a22=a23; a23=a24; a24=a25; a25=a26; a26=a27; a27=a28; a28=a29; a29=a30; a30=a31; a31=a32; a32=a33; a33=a34; a34=a35; a35=a36; a36=a37; a37=a38; a38=a39; a39=a40; a40=a41; a41=a42; a42=a43; a43=a44; a44=a45; a45=a46; a46=a47; a47=a48; a48=a49; a49=a50; a50=a51; a51=a52; a52=a53; a53=a54; a54=a55; a55=a56; a56=a57; a57=a58; a58=a59; a59=a60; a60=a61; a61=a62; a62=a63; a63=a64;
    }
    return 0;
}

2
Oh amico, l'ultimo è solo malvagio. Bello.
Jason C

4

Assemblaggio, 1 operazione

.data

    .space 1         , 1 # (-2)^31
    .space 1610612735, 0
    .space 1         , 1 # (-2)^29
    .space 402653183 , 0
    .space 1         , 1 # (-2)^27
    .space 100663295 , 0
    .space 1         , 1 # (-2)^25
    .space 25165823  , 0
    .space 1         , 1 # (-2)^23
    .space 6291455   , 0
    .space 1         , 1 # (-2)^21
    .space 1572863   , 0
    .space 1         , 1 # (-2)^19
    .space 393215    , 0
    .space 1         , 1 # (-2)^17
    .space 98303     , 0
    .space 1         , 1 # (-2)^15
    .space 24575     , 0
    .space 1         , 1 # (-2)^13
    .space 6143      , 0
    .space 1         , 1 # (-2)^11
    .space 1535      , 0
    .space 1         , 1 # (-2)^9
    .space 383       , 0
    .space 1         , 1 # (-2)^7
    .space 95        , 0
    .space 1         , 1 # (-2)^5 = -32
    .space 23        , 0
    .space 1         , 1 # (-2)^3 = -8
    .space 5         , 0
    .space 1         , 1 # (-2)^1 = -2
    .space 1         , 0
dataZero:
    .space 1         , 0
    .space 1         , 1 # (-2)^0 = 1
    .space 2         , 0
    .space 1         , 1 # (-2)^2 = 4
    .space 11        , 0
    .space 1         , 1 # (-2)^4 = 16
    .space 47        , 0
    .space 1         , 1 # (-2)^6 = 64
    .space 191       , 0
    .space 1         , 1 # (-2)^8
    .space 767       , 0
    .space 1         , 1 # (-2)^10
    .space 3071      , 0
    .space 1         , 1 # (-2)^12
    .space 12287     , 0
    .space 1         , 1 # (-2)^14
    .space 49151     , 0
    .space 1         , 1 # (-2)^16
    .space 196607    , 0
    .space 1         , 1 # (-2)^18
    .space 786431    , 0
    .space 1         , 1 # (-2)^20
    .space 3145727   , 0
    .space 1         , 1 # (-2)^22
    .space 12582911  , 0
    .space 1         , 1 # (-2)^24
    .space 50331647  , 0
    .space 1         , 1 # (-2)^26
    .space 201326591 , 0
    .space 1         , 1 # (-2)^28
    .space 805306367 , 0
    .space 1         , 1 # (-2)^30
    .space 3221225471, 0
    .space 1         , 1 # (-2)^32

.globl isPowNeg2
isPowNeg2:
    movl dataZero(%edi), %eax
    ret

Utilizza un'enorme tabella di ricerca per scoprire se il numero è una potenza di 2. Puoi espanderlo a 64 bit, ma trovare un computer per archiviare molti dati viene lasciato come esercizio al lettore :-P


1
L'indicizzazione di una tabella non è una delle operazioni consentite.
R ..

1
Inoltre, ciò non è chiaramente estendibile a 64 bit. :-)
R ..

In effetti, l'indicizzazione di una tabella non era concepita per essere consentita dalla normativa vigente. Ho specificato "è possibile dichiarare variabili" e "è possibile specificare valori letterali interi" con l'intento di scalari, e semanticamente questo è un array (e pedanticamente parlando non ho permesso tipi di array né ho consentito l'indicizzazione di alcun tipo come uno dei operazioni anche se potresti chiamarlo "addizione" nel contesto dell'assemblatore), ma essendo l'Opportunista che sei ... :)
Jason C

3

C, 31 operazioni

Dimostrazione dal vivo

La mia idea è semplice, se è una potenza di due, quindi se il suo registro è pari allora deve essere positivo, altrimenti il ​​suo registro deve essere strano.

int isPositive(int x) // 6
{
    return ((~x & (~x + 1)) >> 31) & 1;
}

int isPowerOfTwo(int x) // 5
{
    return isPositive(x) & ~(x & (x-1));
}

int log2(int x) // 3
{
    int i = (-1);

    while(isPositive(x))
    {
        i  += 1;
        x >>= 1;
    }

    return i;
}

int isPowerOfNegativeTwo(int x) // 17
{
    return (  isPositive(x) &  isPowerOfTwo(x) & ~(log2(x) % 2) )
         | ( ~isPositive(x) & isPowerOfTwo(-x) & (log2(-x) % 2) );
}

1
In realtà hai fatto meglio di quanto pensi. Una chiamata di funzione conta solo come 1, non come il numero di operatori nella funzione. Quindi, se ho contato correttamente (doppio controllo) hai qualcosa come 6 per isPositive + 5 per isPowerOfTwo + 3 per log2 + 17 per isPowerOfNegativeTwo = 31.
Jason C

1

C, 7 operazioni

int64_t is_power_of_neg2(int64_t n)
{
    int64_t x = n&-n;
    while (x^n) {
        while (x^-n)
            return 0;
        return x & 0xaaaaaaaaaaaaaaaa;
    }
    return x & 0x5555555555555555;
}

o:

C, 13 operazioni senza loop come condizionali

int64_t is_power_of_neg2(int64_t n)
{
    int64_t s = ~(n>>63);
    int64_t a = ((n/2)^s)-s;
    int64_t x = n&-(uint64_t)n; // Cast to define - on INT64_MIN.
    return ~(a/x >> 63) & x & (0xaaaaaaaaaaaaaaaa^s);
}

Spiegazione:

  • n&-nproduce il bit impostato più basso di n.
  • aè il valore assoluto negato di n/2, necessariamente negativo perché /2impedisce l'overflow della negazione.
  • a/xè zero solo se aè una potenza esatta di due; altrimenti è impostato almeno un altro bit ed è maggiore dix del bit più basso, producendo un risultato negativo.
  • ~(a/x >> 63)quindi produce una maschera di bit che è una cosa sola se no -nè una potenza di due, altrimenti tutti zeri.
  • ^sviene applicato alla maschera per controllare il segno di nper vedere se è un potere di -2.

1

PHP, 3 operazioni

ternario e ifnon sono ammessi; quindi abusiamo while:

function f($n)
{
    while ($n>>1)               # 1. ">>1"
    {
        while ($n&1)            # 2. "&1"
            return 0;
        return f($n/-2|0);      # 3. "/-2" ("|0" to turn it into integer division)
    }
    return $n;
}
  1. $n>>1: se il numero è 0 o 1, restituisce il numero
  2. $n&1: se il numero è dispari, restituisce 0
  3. else test $n/-2(+ cast in int)

0

JavaScript ES6, 7 operazioni

x=>{
  while(x&1^1&x/x){
    x/=-2;x=x|0
  }
  while(x&0xfffffffe)x-=x
  return x
}

Provalo online!

Spiegazione

while(x&1^1&x/x)

Mentre x! = 0 e x% 2 == 0 4 operazioni
x / x è uguale a 1 purché x non sia 0 (0/0 fornisce NaN che viene valutato come falso)
e bit a bit e
x & 1 ^ 1 è uguale a 1 se x è pari (xe 1) xo 1

x/=-2;x=x|0

Questa è la forma di divisione definita dalla domanda 1 op

while(x&0xfffffffe)  

Mentre x! = 1 and x! = 0 1 op
La condizione necessaria per uscire quando x == 0 o x == 1 in quanto quei due sono i valori di ritorno e l'inserimento di un ciclo infinito non sarebbe produttivo. Questo potrebbe teoricamente essere esteso per valori maggiori aumentando il numero esadecimale. Attualmente funziona fino a ± 2 ^ 32-1

x-=x

Imposta x su 0 1 op
Mentre avrei potuto usare return 0 per 0 operazioni, ho sentito che ogni ciclo while che è rotto da un'altra istruzione sembra troppo un imbroglio.

return x

restituisce x (1 se potenza di -2, 0 altrimenti)

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.