Wiki

Clone wiki

CPL01 / goede_antwoorden

21 goede antwoorden op een eenvoudige programmeervraag

Op sommige vragen is maar één goed antwoord mogelijk. Op een programmeervraag kun je vaak heel veel goede antwoorden geven. Als voorbeeld zal ik op deze pagina 21 goede antwoorden laten zien op (een relatief eenvoudige) programmeervraag. Het is best leerzaam of te kijken of je al deze antwoorden begrijpt.

De vraag

Een perfect getal is een getal dat gelijk is aan zijn eigen delers (behalve zichzelf). Bijvoorbeeld: 28 is (slechts) deelbaar door 14, 7, 4, 2 en 1 en 14 + 7 + 4 + 2 + 1 = 28, dus 28 is een perfect getal. Zie eventueel voor verdere uitleg https://nl.wikipedia.org/wiki/Perfect_getal. Het is nog niet bekend hoeveel perfecte getallen er zijn. Er zijn slechts 5 perfecte getallen die in een variabele van het type int passen, namelijk 6, 28, 496, 8128 en 33550336. Er zijn veel meer perfectie getallen bekend maar die zijn allemaal groter van 2^31 (twee tot de macht eenendertig) en die passen dus niet in een variabele van het type int.

Schrijf een functie isPerfect die bepaald of een getal van het type int perfect is. Als dit zo is moet de functie de waarde 1 teruggeven en als dit niet zo is moet de functie de waarde 0 teruggeven. Het is niet nodig om rekenkundig te bepalen of het getal perfect is. Je kunt het als argument meegegeven getal simpel vergelijken met de 5 perfecte getallen die in een variabele van het type int passen.

De antwoorden

Bij onderstaande antwoorden gebruiken we vergelijkingsoperatoren zoals == en != die in C de waarde 0 teruggeven (als de vergelijking onwaar oftewel false oplevert) of 1 (als de vergelijking waar oftewel true oplevert). We maken ook gebruik van het feit dat de booleaanse operatoren || (or), && (and) en ! (not) 0 (false) of 1 (true) teruggeven.

Antwoord 1

Dit is waarschijnlijk het meest eenvoudige antwoord. De operator || geeft (meteen) true terug als de eerste operand de waarde true heeft. Dus als de vergelijking getal == 6 true oplevert dan worden de overige vergelijkingen niet meer uitgevoerd maar wordt meteen een 1 geretourneerd.

#!C
int isPerfect(int getal)
{
    return getal == 6 || getal == 28 || getal == 496 || getal == 8128 || getal == 33550336;
}

Antwoord 2

Bij dit antwoord wordt de waarde 0 of 1 expliciet geretourneerd. Dit is niet nodig (zoals je in antwoord 1 al hebt gezien), maar wordt door beginnende programmeurs toch vaak gedaan.

#!C
int isPerfect(int getal)
{
    if (getal == 6 || getal == 28 || getal == 496 || getal == 8128 || getal == 33550336)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

Antwoord 3

Dit antwoord is bijna hetzelfde als antwoord 2. Er wordt in dit antwoord gebruik gemaakt van een if in plaats van een if ... else. Omdat de code in de if een return-statement bevat maakt dat in dit geval niet uit.

#!C
int isPerfect(int getal)
{
    if (getal == 6 || getal == 28 || getal == 496 || getal == 8128 || getal == 33550336)
    {
        return 1;
    }
    return 0;
}

Antwoord 4

Bij dit antwoord wordt het gedrag van ||-operator helemaal uitgeschreven met if-instructies.

#!C
int isPerfect(int getal)
{
    if (getal == 6)
    {
        return 1;
    }
    if (getal == 28)
    {
        return 1;
    }
    if (getal == 496)
    {
        return 1;
    }
    if (getal == 8128)
    {
        return 1;
    }
    if (getal == 33550336)
    {
        return 1;
    }
    return 0;
}

Antwoord 5

Bij dit antwoord wordt het gedrag van ||-operator helemaal uitgeschreven met if ... else-instructies.

#!C
int isPerfect(int getal)
{
    if (getal == 6)
    {
        return 1;
    }
    else
    {
        if (getal == 28)
        {
            return 1;
        }
        else
        {
            if (getal == 496)
            {
                return 1;
            }
            else
            {
                if (getal == 8128)
                {
                    return 1;
                }
                else
                {
                    if (getal == 33550336)
                    {
                        return 1;
                    }
                    else
                    {
                        return 0;
                    }
                }
            }
        }
    }
}

Antwoord 6

Dit antwoord is gevonden door de wetten van De Morgan, zie eventueel https://nl.wikipedia.org/wiki/Wetten_van_De_Morgan, toe te passen op antwoord 2. De operator ! is de booleaanse not-operator.

#!C
int isPerfect(int getal)
{
    return !(!(getal == 6) && !(getal == 28) && !(getal == 496) && !(getal == 8128) && !(getal == 33550336));
}

Antwoord 7

Dit antwoord is gevonden door in antwoord 6 te verwerken dat !(a == b) hetzelfde is als a != b.

#!C
int isPerfect(int getal)
{
    return !(getal != 6 && getal != 28 && getal != 496 && getal != 8128 && getal != 33550336);
}

Antwoord 8

Dit antwoord is gevonden door het gedrag van de &&-operator in antwoord 7 helemaal uit te schijven met if-instructies.

#!C
int isPerfect(int getal)
{
    if (getal != 6)
    {
        if (getal != 28)
        {
            if (getal != 496)
            {
                if (getal != 8128)
                {
                    if (getal != 33550336)
                    {
                        return 0;
                    }
                }
            }
        }
    }
    return 1;
}

Antwoord 9

Dit antwoord is gevonden door het gedrag van de &&-operator in antwoord 7 helemaal uit te schijven met if ... else-instructies.

#!C
int isPerfect(int getal)
{
    if (getal != 6)
    {
        if (getal != 28)
        {
            if (getal != 496)
            {
                if (getal != 8128)
                {
                    if (getal != 33550336)
                    {
                        return 0;
                    }
                    else
                    {
                        return 1;
                    }
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                return 1;
            }
        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 1;
    }
}

Antwoord 10

Bij dit antwoord worden de returnwaarden van de vergelijkingen uit antwoord 1 bij elkaar opgeteld. Als deze som 1 is, dan is de parameter getal een perfect getal en als de som 0 oplevert, dan is dat niet zo. Het grote verschil met antwoord 1 is dat bij het gebruik van de operator + alle vijf de vergelijkingen altijd zullen worden uitgevoerd. Dit antwoord is dus minder efficiënt dan antwoord 1. Bovendien moeten we de vergelijkingen tussen haakjes worden gezet omdat de ==-operator een lagere prioriteit heeft dan de +-operator. Zie eventueel http://en.cppreference.com/w/c/language/operator_precedence.

#!C
int isPerfect(int getal)
{
    return (getal == 6) + (getal == 28) + (getal == 496) + (getal == 8128) + (getal == 33550336);
}

Antwoord 11

Bij dit antwoord worden de returnwaarden van de vergelijkingen uit antwoord 7 bij elkaar opgeteld. Als deze som 4 is, dan is de parameter getal een perfect getal en als de som 5 is, dan is dat niet zo. Het grote verschil met antwoord 7 is dat bij het gebruik van de operator + alle vijf de vergelijkingen altijd zullen worden uitgevoerd. Dit antwoord is dus minder efficiënt dan antwoord 7. Bovendien moeten we de vergelijkingen tussen haakjes worden gezet omdat de !=-operator een lagere prioriteit heeft dan de +-operator. Zie eventueel http://en.cppreference.com/w/c/language/operator_precedence.

#!C
int isPerfect(int getal)
{
    return (getal != 6) + (getal != 28) + (getal != 496) + (getal != 8128) + (getal != 33550336) == 4;
}

Antwoord 12

Dit antwoord is een variant op antwoord 11 waarbij slim gebruik gemaakt is van het feit dat de som alleen 4 of 5 kan opleveren.

#!C
int isPerfect(int getal)
{
    return 5 - ((getal != 6) + (getal != 28) + (getal != 496) + (getal != 8128) + (getal != 33550336));
}

Antwoord 13

Dit antwoord is een variant op antwoord 12 waarbij de haakjes rond de som zijn weggewerkt waardoor de +-operatoren veranderen in --operatoren.

#!C
int isPerfect(int getal)
{
    return 5 - (getal != 6) - (getal != 28) - (getal != 496) - (getal != 8128) - (getal != 33550336);
}

Antwoord 14

Bij dit antwoord worden de returnwaarden van de vergelijkingen uit antwoord 7 met elkaar vermenigvuldigd. Als dit product 0 is, dan is de parameter getal een perfect getal en als het product 1 is, dan is dat niet zo. Het grote verschil met antwoord 7 is dat bij het gebruik van de operator * alle vijf de vergelijkingen altijd zullen worden uitgevoerd. Dit antwoord is dus minder efficiënt dan antwoord 7. Bovendien moeten we de vergelijkingen tussen haakjes worden gezet omdat de !=-operator een lagere prioriteit heeft dan de *-operator. Zie eventueel http://en.cppreference.com/w/c/language/operator_precedence.

#!C
int isPerfect(int getal)
{
    return !((getal != 6) * (getal != 28) * (getal != 496) * (getal != 8128) * (getal != 33550336));
}

Antwoord 15

Dit antwoord is een variant op antwoord 14 waarbij het inverteren van de waarde van het product op een andere manier is geïmplementeerd. Er zijn nu minder haakjes nodig omdat de operator - een lagere prioriteit heeft dan de operator *.

#!C
int isPerfect(int getal)
{
    return 1 - (getal != 6) * (getal != 28) * (getal != 496) * (getal != 8128) * (getal != 33550336);
}

Antwoord 16

Bij dit antwoord maken we gebruik van de ? ... :-operator. Deze operator wordt de conditionele operator genoemd. Zie http://en.cppreference.com/w/c/language/operator_other#Conditional_operator als je deze operator nog niet kent. Dit antwoord is een variant op antwoord 5 waarbij de if ... else-instructies vervangen zijn door ? ... :-operatoren.

#!C
int isPerfect(int getal)
{
    return getal == 6 ? 1 : getal == 28 ? 1 : getal == 496 ? 1 : getal == 8128 ? 1 : getal == 33550336 ? 1 : 0;
}

Antwoord 17

Bij dit antwoord maken we gebruik van de ? ... :-operator. Deze operator wordt de conditionele operator genoemd. Zie http://en.cppreference.com/w/c/language/operator_other#Conditional_operator als je deze operator nog niet kent. Dit antwoord is een variant op antwoord 9 waarbij de if ... else-instructies vervangen zijn door ? ... :-operatoren.

#!C
int isPerfect(int getal)
{
    return getal != 6 ? getal != 28 ? getal != 496 ? getal != 8128 ? getal != 33550336 ? 0 : 1 : 1 : 1 : 1 : 1;
}

Antwoord 18

Bij dit antwoord worden de returnwaarden van de vergelijkingen uit antwoord 1 met elkaar gecombineerd met een bitgewijze or-operator |. Deze |-operator moet je niet verwarren met de logische or-operator ||. De bitgewijze or-operator voert (zoals de naam al zegt) een or-operatie uit op alle bits van de operanden. Dus bijvoorbeeld 5 | 12 geeft als resultaat 13 want op alle bits van de getallen 5 en 12 wordt bitgewijs een or-bewerking uitgevoerd:

#!None
00000000 00000000 00000000 00000101    
00000000 00000000 00000000 00001100
----------------------------------- OR
00000000 00000000 00000000 00001101    

De logische or-operator voert slechts één or-bewerking uit waarbij een operand met de waarde 0 als false wordt gezien en elke andere waarde als true wordt gezien. Het resultaat is 0 (false) of 1 (true). Dus bijvoorbeeld 5 || 12 geeft als resultaat 1 want true or true geeft true.

Omdat het resultaat van elke vergelijking alleen 0 of 1 kan zijn kunnen we in dit geval ook de bitgewijze or-operator gebruiken.

Het grote verschil met antwoord 1 is dat bij het gebruik van de operator | alle vijf de vergelijkingen altijd zullen worden uitgevoerd. Dit antwoord is dus minder efficiënt dan antwoord 1.

#!C
int isPerfect(int getal)
{
    return getal == 6 | getal == 28 | getal == 496 | getal == 8128 | getal == 33550336;
}

Antwoord 19

Bij dit antwoord worden de returnwaarden van de vergelijkingen uit antwoord 7 met elkaar gecombineerd met een bitgewijze and-operator &. Deze &-operator moet je niet verwarren met de logische and-operator &&. De bitgewijze and-operator voert (zoals de naam al zegt) een and-operatie uit op alle bits van de operanden. Dus bijvoorbeeld 5 & 12 geeft als resultaat 4 want op alle bits van de getallen 5 en 12 wordt bitgewijs een and-bewerking uitgevoerd:

#!None
00000000 00000000 00000000 00000101    
00000000 00000000 00000000 00001100
----------------------------------- AND
00000000 00000000 00000000 00000100    

De logische and-operator voert slechts één and-bewerking uit waarbij een operand met de waarde 0 als false wordt gezien en elke andere waarde als true wordt gezien. Het resultaat is 0 (false) of 1 (true). Dus bijvoorbeeld 5 && 12 geeft als resultaat 1 want true and true geeft true.

Omdat het resultaat van elke vergelijking alleen 0 of 1 kan zijn kunnen we in dit geval ook de bitgewijze and-operator gebruiken.

Het grote verschil met antwoord 7 is dat bij het gebruik van de operator & alle vijf de vergelijkingen altijd zullen worden uitgevoerd. Dit antwoord is dus minder efficiënt dan antwoord 7.

#!C
int isPerfect(int getal)
{
    return !(getal != 6 & getal != 28 & getal != 496 & getal != 8128 & getal != 33550336);
}

Antwoord 20

Dit antwoord is een variant van antwoord 7. Bij dit antwoord is gebruik gemaakt van de bitgewijze not-operator ~. Deze ~-operator moet je niet verwarren met de logische not-operator !. De bitgewijze not-operator voert (zoals de naam al zegt) een not-operatie uit op alle bits van de operand. Dus bijvoorbeeld ~5 geeft als resultaat -6 want op alle bits van het getal 5 wordt bitgewijs een not-bewerking uitgevoerd:

#!None
00000000 00000000 00000000 00000101    
----------------------------------- NOT
11111111 11111111 11111111 11111010

Bij een variabel van het type int wordt de two's-complement codering gebruikt. De binaire waarde 11111111 11111111 11111111 11111010 komt dus overeen met de decimale waarde -6.

De logische not-operator voert slechts één not-bewerking uit waarbij een operand met de waarde 0 als false wordt gezien en elke andere waarde als true wordt gezien. Het resultaat is 0 (false) of 1 (true). Dus bijvoorbeeld !5 geeft als resultaat 0 want not true geeft false.

Omdat het resultaat van de and-operaties alleen 0 of 1 kan zijn kunnen we in dit geval niet zonder meer gebruik maken van de bitgewijze not-operator.

Omdat de bitwise not van 0 -1 oplevert en de bitwise not van 1 -2 oplevert is nog een correctie nodig om het gewenste antwoord te krijgen. Het is dus in dit geval veel eenvoudiger om de operator ! te gebruiken zoals in antwoord 7.

#!C
int isPerfect(int getal)
{
    return 2 + ~(getal != 6 && getal != 28 && getal != 496 && getal != 8128 && getal != 33550336);
}

Antwoord 21

Dit antwoord is een variant van antwoord 7 waarbij de !-operator vervangen is door een extra vergelijking.

#!C
int isPerfect(int getal)
{
    return (getal != 6 && getal != 28 && getal != 496 && getal != 8128 && getal != 33550336) == 0;
}

Updated