web-dev-qa-db-fra.com

Fonction de conception f(f(n)) == -n

Une question que j'ai eue lors de ma dernière interview:

Concevoir une fonction f, telle que:

f(f(n)) == -n

n est un 32 bits entier signé; vous ne pouvez pas utiliser l'arithmétique des nombres complexes.

Si vous ne pouvez pas concevoir une telle fonction pour toute la plage de nombres, concevez-la pour la plage la plus large possible.

Des idées?

838
Hrvoje Prgeša

Objective-C

Cela fonctionne pour tous les nombres sauf "-1".

Si vous devez utiliser int pour utiliser NSInt, vous pouvez définir -1 comme valeur pour NULL, puis les convertir une seconde fois en +1, mais j'estime que NSInt _ trompe l'intention du demandeur.


f (n):

-(int)f:(int)n {
    if (abs(n)==1) {
        n = -1;
    } else {
        if (abs(n)%2) {//o
            if (n>0) {//+
                n--;
                n*=+1;
            } else if (n<0) {//-
                n++;
                n*=+1;
            }
        } else {//e
            if (n>0) {//+
                n++;
                n*=-1;
            } else if (n<0) {//-
                n--;
                n*=-1;
            }
        }
    }
    return n;
}

Bien sûr, tout cela pourrait être réduit à une ligne, mais d'autres personnes pourraient ne pas être en mesure de lire le texte ...


Quoi qu'il en soit, j'ai stocké la logique BOOLEAN dans l'état du nombre impair ou pair.

0
Albert Renshaw

J'ai essayé le golf cette réponse par Rodrick Chapman .

Sans branches: 74 caractères

int f(int i){return(-((i&1)<<1)|1)*i-(-((i>>>31)<<1)|1)*(((i|-i)>>31)&1);}

Avec des branches, Java style: 58 caractères

int f(int i){return i==0?0:(((i&1)==0?i:-i)+(i>0?-1:1));}

Avec des branches, style C: 52 caractères

int f(int i){return i?(((i&1)?-i:i)+(i>0?-1:1)):0;}

Après un test rapide mais valide, la version avec branches s’avère 33% plus rapide sur ma machine. (Jeu de données aléatoires de nombres positifs et négatifs, suffisamment de répétition et empêchant le compilateur d'optimiser le code, avec échauffement.) Ce n'est pas si surprenant, étant donné le nombre d'opérations dans la version non ramifiée et la bonne prédiction de branche possible du fait du fait que la fonction est appelée deux fois: f(f(i)). Lorsque je modifie le point de repère pour mesurer: f(i), la version avec branche est seulement 28% plus rapide. Je pense que cela prouve que la prédiction de branche a eu un effet positif dans le premier cas. Preuve supplémentaire: lors des tests avec f(f(f(f(i)))), il s'avère que la version avec branche est 42% plus rapide.

0
Martijn Courteaux

Solution dans le Wolfram Language :

f[f[n_]] := -n

Application:

In[2]:= f[f[10]]                                                                                                                                                                                                                                                                              
Out[2]= -10
In[3]:= f[10]                                                                                                                                                                                                                                                                                 
Out[3]= f[10]

Comme la question ne dit rien de la valeur de f (n), f [n] reste non évaluée.

0
sakra

Une autre solution de triche en C++, la surcharge des opérateurs.

struct func {
    int n;
    func operator()(int k) { n = -k; return *this; }
    int operator()(const func &inst) { return inst.n; }
} f;
0
skies457

f (x) = le point (x) pivoté de 90 degrés dans le sens inverse des aiguilles d'une montre autour de l'origine dans un système de coordonnées cartésien 2D. Les entrées d'un seul nombre x sont supposées être (x, 0), et les sorties ayant y = 0 sont fournies sous la forme du nombre unique x.

object f: (object) x {
    if (x.length == 1)
        x = (x, 0)
    swap = x[0]
    x[1] = x[0]
    x[0] = -swap
    if (x[1] == 0)
        x = x[0]
    return x
0
David Stein

F#

let f n =
    match n with
    | n when n % 2 = 0 -> -n + System.Math.Sign n
    | _ -> n - System.Math.Sign -n

n tel que System.Int32.MinValue < n < System.Int32.MaxValue.

0
Tajomaru

Javascript

function f(n)  { 
        return typeof n === "number" ? 
        function() {return -n} : 
        n();
}
0
ssh

D'après les questions que les intervieweurs de Microsoft/Google posent habituellement dans leurs interviews, je pense que le demandeur s'appuie sur une solution simple, innovante et légère, qui utilisera des opérations au niveau du bit, et non des réponses compliquées de haut niveau.

Inspiré par la réponse de @eipipuz, j'ai écrit cette fonction C++ (mais je ne l'ai pas exécutée):

int32_t f(int32_t n){
    int32_t temp = n & 00111111111111111111111111111111;
    x = n >> 30;
    x++;
    x = x << 30;
    return x | temp;
}

Il stocke les deux bits les plus à gauche de n dans x, ajoute 1 à x, puis les remplace comme les deux bits les plus à gauche de n encore.

Si nous continuons à courir f (n) avec un autre f (n) en tant que paramètre n, les deux bits les plus à gauche tourneront comme ceci:

00 -> 01 -> 10 -> 11 -> 00 ...

Notez que les 30 bits les plus à droite ne changent pas. Exemples pour les entiers 8 bits:

Exemple 1:

  • > f(00001111) = 01001111
  • > f(01001111) = 10001111 [valeur négative de la valeur d'origine, 00001111]

Exemple 2:

  • > f(11101010) = 00101010
  • > f(00101010) = 01101010 [Négatif de la valeur d'origine, 11101010]
0
Alisa

J'avoue que je tricherais, mais que je répondrais quand même aux exigences. C'est de la magie programmée, pas vraiment des mathématiques. Cela fonctionne pour toute la gamme, sauf -2 ^ 31.

int f(int n)
{
    static bool eFlag = false; // Only executed once
    eFlag = !eFlag;
    return eFlag?-n:n;
}
0
Hameer Abbasi