2010-07-10 17 views
5

Hice un programa usando C para encontrar si el año ingresado es bisiesto o no. Pero lamentablemente no está funcionando bien. Dice que un año es un salto y que el año anterior no es un salto.Cómo encontrar año bisiesto programáticamente en C

#include<stdio.h> 
#include<conio.h> 
int yearr(int year); 
void main(void) 
{ 
    int year; 
    printf("Enter a year:"); 
    scanf("%d",&year); 
    if(!yearr(year)) 
    { 
     printf("It is a leap year."); 
    } 
    else 
    { 
    printf("It is not a leap year"); 
    } 


getch(); 
} 
int yearr(int year) 
{ 
    if((year%4==0)&&(year/4!=0)) 
    return 1; 
    else 
    return 0; 
} 

Después de leer los comentarios que he editado mi codificación como:

#include<stdio.h> 
#include<conio.h> 
int yearr(int year); 
void main(void) 
{ 
    int year; 
    printf("Enter a year:"); 
    scanf("%d",&year); 
    if(!yearr(year)) 
    { 
     printf("It is a leap year."); 
    } 
    else 
    { 
    printf("It is not a leap year"); 
    } 


getch(); 
} 
int yearr(int year) 
{ 
    if((year%4==0) 
    { 
    if(year%400==0) 
    return 1; 
    if(year%100==0) 
    return 0; 
    } 
    else 
    return 0; 
} 
+1

¿Funcionó? Además, la legibilidad del código es importante, por lo que 'yearr' es un nombre pobre para una función para encontrar si un año es bisiesto. 'main' devuelve' int' en C, no 'void'. –

+0

Al compilar el código revisado, GCC dice: 'En la función 'yearr': yearr.c: 12: advertencia: el control llega al final de la función no válida'. Si sangra su código correctamente, le resultará más fácil ver por qué es así, basta con decir que si el año es divisible entre 4 pero no divisible entre 100, no le dirá a la persona que llama si eso es o no Un año bisiesto. –

+0

'if (! Yearr (año)) { printf (" Es un año bisiesto "); } else { printf ("No es un año bisiesto"); } ' En lugar de lo anterior uno ' si (yearr (año)) { printf ("No es un año bisiesto."); } else { printf ("Es un año bisiesto"); } ' ¿No crees que el siguiente es fácil de entender? –

Respuesta

14

Su lógica para determinar un año bisiesto es incorrecta. Esto debería ayudarle a empezar (de Wikipedia):

if year modulo 400 is 0 
     then is_leap_year 
else if year modulo 100 is 0 
     then not_leap_year 
else if year modulo 4 is 0 
     then is_leap_year 
else 
     not_leap_year 

x modulo y significa que el resto de x dividido por y. Por ejemplo, 12 módulo 5 es 2.

2

De Wikipedia article on Leap year:

if (year modulo 4 is 0) and (year modulo 100 is not 0) or (year modulo 400 is 0) 
    then is_leap_year 
else 
    not_leap_year 
Reglas
+0

Sí, este es el hecho. nice one –

1

http://www.wwu.edu/depts/skywise/leapyear.html

año bisiesto

Hay un año bisiesto cada año cuyo número es perfectamente divisible por cuatro - a excepción de los años que son ambos divisibles por 100 y no divisibles por 400. La segunda parte de la regla tiene efecto siglo años. Por ejemplo; los años del siglo 1600 y 2000 son años bisiestos, pero los años del siglo 1700, 1800 y 1900 no lo son. Esto significa que tres veces de cada cuatrocientos años hay ocho años entre años bisiestos.

1
if(year%400 ==0 || (year%100 != 0 && year%4 == 0)) 
    { 
     printf("Year %d is a leap year",year); 
    } 
    else 
    { 
     printf("Year %d is not a leap year",year); 
    } 

cambio que, como anteriormente. Lea también this.

+6

No es una buena idea dar solución a un problema de tarea. –

2

El problema con su código es que está devolviendo un valor distinto de cero de yearr si cree que el año es bisiesto. Entonces no necesita el ! en su declaración if.

6
int isLeapYear(int year) 
{ 
    return (year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0)); 
} 
+0

¿Por qué el voto a favor? :( – st0le

+0

Ineficiencia, principalmente debido al orden de ejecución. Mod 400 y Mod 100 deben calcularse cada vez, cuando el término Mod 4 podría haberlos descartado el 75% del tiempo (ver mi respuesta más arriba). ¿Menor? en el esquema de las cosas. Sin embargo, cuando se busca una respuesta de referencia, el algoritmo de Wikipedia se repite demasiado a menudo como uno bueno (y no es muy bueno en absoluto). Para algunos, este detalle no es importante, pero para mí, el algoritmo de Wikipedia es como escribir 2/4 en vez de 1/2. –

+0

@ KevinP.Rice, pregunta de 2 años pero voy a morder. Si ves el código de OP, es claramente un principiante y nunca ha pedido una solución eficaz. implementación. Teniendo en cuenta el contexto, si yo fuera un profesor, nunca recomendaría el OP para usar su respuesta. Además, siempre escogería código legible sobre código micro-optimizado cualquier día. Pero para cada uno el suyo. ¡Salud! – st0le

3

Aunque la lógica que divide primero por 400 es impecable, no es tan eficiente desde el punto de vista computacional como dividir por 4 primero. Usted puede hacer eso con la lógica:

#define LEAPYEAR(y) ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0)) 

Esto divide por 4 para cada valor, pero para 3/4 de ellos, la prueba termina allí. Para el 1/4 que pasa la primera prueba, luego se divide por 100, eliminando 24/25 valores; para el restante 1 de cada 100, también se divide por 400, obteniendo una respuesta final. Por supuesto, esto no es un gran ahorro.

+0

Deberías reemplazar 'y% 4' con' y & 3', y reemplazar 'y% 400' con' y & 15'. Justificación: la división del módulo es lenta en algunas plataformas, mientras que un único AND a nivel de bit es generalmente un ciclo de instrucción. Algunos compiladores de idiomas realizan esta optimización de forma automática, pero al copiarla en el código se garantiza. Modulo 400 puede ser reemplazado con '& 15' porque 16 es un factor de 400 pero no 100 (o 200). Para sistemas de 8 bits, el '& 15' es mucho más fácil de manejar. Técnicamente, '% 100' puede reemplazarse con'% 25' pero esto probablemente no sea una mejora para ningún sistema. –

+0

@Kevin P. Rice ¿Reemplazará 'y% 4' con' y & 3' funcionará correctamente si los enteros no son complemento de 2 y 'y <0'? – chux

+0

@ KevinP.Rice: El cambio de Julian a Gregorian es un poco más complejo que "sucedió en 1582". Muchos países católicos cambiaron en 1584; los países bajo dominio británico cambiaron en 1752; otros países cambiaron en diferentes momentos (Rusia en el siglo 20, la iglesia ortodoxa rusa todavía no ha cambiado, AFAIK). Compruebe la salida de 'cal 9 1752' en una máquina Unix-ish. Además, para los valores negativos del año, debe luchar con la presencia o la ausencia de un año 0. –

94

más eficiente la prueba del año bisiesto:

if ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0)) 
{ 
    /* leap year */ 
} 

Este código es válido en C, C++, C#, Java y muchos otros lenguajes como C.El código utiliza una sola expresión VERDADERO/FALSO que consiste en tres pruebas separadas:

  • cuarta prueba del año: year & 3
  • prueba de 100 años: year % 25
  • prueba el año 400o: year & 15

A La discusión completa de cómo funciona este código aparece a continuación, pero primero se necesita una discusión sobre el algoritmo de Wikipedia:

El algoritmo de Wikipedia es INEFFICIENTE/NO RESPONSABLE

Wikipedia ha publicado un algoritmo de pseudocódigo (Ver: Wikipedia: Leap year - Algorithm) que ha sido sometido a constante edición, opinión y vandalismo.

NO IMPLEMENTE WIKIPEDIA ALGORITHM!

Uno de los más antiguos (e ineficientes) algoritmos Wikipedia apareció como sigue:

if year modulo 400 is 0 then 
    is_leap_year 
else if year modulo 100 is 0 then 
    not_leap_year 
else if year modulo 4 is 0 then 
    is_leap_year 
else 
    not_leap_year 

El algoritmo anterior es ineficiente porque siempre realiza las pruebas para el año 400o y 100o año, incluso durante años que fallaría rápidamente la "prueba del 4 ° año" (la prueba del módulo 4) — que es el 75% del tiempo. Al reordenar el algoritmo para realizar la prueba del 4 ° año primero, aceleramos significativamente las cosas.

"más eficiente" pseudo-código del algoritmo

me proporcionó el siguiente algoritmo para Wikipedia (más de una vez):

if year is not divisible by 4 then not leap year 
else if year is not divisible by 100 then leap year 
else if year is divisible by 400 then leap year 
else not leap year 

Este "más eficientes" pseudo-código simplemente cambia el orden de las pruebas para que la división por 4 se lleve a cabo primero, seguido de las pruebas que ocurren menos frecuentemente. Debido a que "año" no se divide en cuatro el 75 por ciento de las veces, el algoritmo finaliza después de una sola prueba en tres de cuatro casos.

NOTA: He luchado varios editores de Wikipedia para mejorar el algoritmo publicado allí, argumentando que muchos novatos — y profesionales — programadores llegan rápidamente a la página de Wikipedia (debido a los mejores anuncios de motor de búsqueda) y poner en práctica la Wikipedia pseudo-código sin más investigación. Los editores de Wikipedia repudiaron y eliminaron todos los intentos que hice para mejorar, anotar o incluso meramente a pie de página el algoritmo publicado. Aparentemente, sienten que encontrar eficiencias es el problema del programador. Eso puede ser cierto, ¡pero muchos programadores están demasiado apurados para realizar investigaciones sólidas!

discusión de "más eficiente" LEAP TEST AÑO

Bitwise-Y en lugar del módulo:

He substituido dos de las operaciones de módulo en el algoritmo de Wikipedia con bit a bit-AND operaciones. ¿Porque y como?

Realizar un cálculo de módulo requiere división.A menudo no se lo piensa dos veces cuando se programa una PC, pero cuando se programan microcontroladores de 8 bits incrustados en dispositivos pequeños, es posible que la CPU no pueda realizar una función de división de forma nativa. En tales CPU, la división es un proceso arduo que implica bucle repetitivo, cambio de bit y operaciones de suma/resta que es muy lento. Es muy deseable evitar.

Resulta que el módulo de potencias de dos puede conseguirse alternativamente mediante un bit a bit-operación AND (véase: Wikipedia: Modulo operation - Performance Issues):

x% 2^n == x & (2^n - 1)

Muchos compiladores de optimización convertirán tales operaciones de módulo a bitwise-Y para usted, pero los compiladores menos avanzados para CPU más pequeñas y menos populares pueden no hacerlo. Bitwise-AND es una instrucción única en cada CPU.

Mediante la sustitución de los modulo 4 y modulo 400 pruebas con & 3 y & 15 (ver más abajo: 'Factoring para reducir matemáticas') podemos asegurar que los resultados de código más rápido sin necesidad de utilizar una operación de división mucho más lento.

No existe una potencia de dos igual a 100. Por lo tanto, estamos obligados a seguir utilizando la operación de módulo para la prueba de 100 años, sin embargo, 100 se reemplaza por 25 (ver a continuación).

Factoring para simplificar los cálculos:

Además de utilizar bit a bit-Y para reemplazar operaciones de módulo, es posible tener en cuenta dos diferencias adicionales entre el algoritmo de Wikipedia y la expresión optimizada:

  • modulo 100 se sustituye por modulo 25
  • modulo 400 se sustituye por & 15

La prueba de 100 años utiliza modulo 25 en lugar de modulo 100. Podemos hacer esto debido a 100 factores de hasta 2 x 2 x 5 x 5. Debido a que la prueba del 4to año ya verifica factores de 4, podemos eliminar ese factor de 100, dejando 25. Esta optimización es probablemente insignificante para casi todas las implementaciones de CPU (ya que tanto 100 como 25 caben en 8 bits).

La prueba del año 400 utiliza & 15 que es equivalente a modulo 16. De nuevo, podemos hacer esto porque 400 factores salen a 2 x 2 x 2 x 2 x 5 x 5. Podemos eliminar el factor de 25 que se prueba con la prueba de 100 años, dejando 16. No podemos seguir reduciendo 16 porque 8 es un factor de 200, por lo que eliminar más factores produciría un positivo no deseado por 200 años.

La optimización de 400 años es muy importante para las CPU de 8 bits, primero, porque evita la división; pero, más importante, porque el valor 400 es un número de 9 bits que es mucho más difícil de tratar en una CPU de 8 bits.

de cortocircuito lógico y/o operadores:

El final, y más importante, la optimización utilizados son el cortocircuito operadores ('& & ') y OR (' ||') Y lógico (ver: Wikipedia: Short-circuit evaluation), que se implementan en la mayoría de los lenguajes tipo C. Los operadores de cortocircuito se llaman así porque no se molestan en evaluar la expresión del lado derecho si la expresión del lado izquierdo, por sí misma, dicta el resultado de la operación.

Por ejemplo: si el año es 2003, entonces year & 3 == 0 es falso. No hay forma de que las pruebas en el lado derecho de la Y lógica puedan hacer que el resultado sea verdadero, por lo que no se evalúa nada más.

Al realizar la prueba del cuarto año primero, solo la prueba del cuarto año (una simple Y a nivel de bits) se evalúa tres cuartas partes (75 por ciento) del tiempo. Esto acelera enormemente la ejecución del programa, especialmente porque evita la división necesaria para la prueba de 100 años (la operación del módulo 25).

NOTA DE COLOCACIÓN PARÉNTESIS

Un comentarista sintió paréntesis, estaban fuera de lugar en mi código y sugirió las sub-expresiones serán reagrupados alrededor del operador lógico AND (en lugar de alrededor de la lógica OR), de la siguiente manera:

if (((year & 3) == 0 && (year % 25) != 0) || (year & 15) == 0) { /* LY */ } 

Lo anterior es incorrecto. El operador AND lógico tiene una precedencia mayor que el OR lógico y se evaluará primero con o sin los nuevos paréntesis. Los paréntesis alrededor de los argumentos lógicos Y no tienen ningún efecto. Esto podría llevar a eliminar los sub-grupos enteramente:

if ((year & 3) == 0 && (year % 25) != 0 || (year & 15) == 0) { /* LY */ } 

Pero, en ambos casos anteriormente, se evalúa la parte derecha de la lógica OR (la prueba año 400a) casi cada vez (es decir, , años no divisibles por 4 y 100). Por lo tanto, una optimización útil ha sido erróneamente eliminada.

Los paréntesis en mi código original implementar la solución más optimizada:

if ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0)) { /* LY */ } 

Aquí, el OR lógico sólo se evalúa por año divisible por 4 (debido a la corta-circuito AND). El lado derecho del OR lógico solo se evalúa por años divisibles por 4 y 100 (debido al cortocircuito O).

NOTA PARA C/C++ PROGRAMADORES

C/C++ programadores pueden considerar esta expresión está más optimizado:

if (!(year & 3) && ((year % 25) || !(year & 15))) { /* LY */ } 

Esto no es más optimizado! Si bien las pruebas explícitas == 0 y != 0 se eliminan, se vuelven implícitas y aún se realizan. Peor aún, el código ya no es válido en lenguajes fuertemente tipados como C# donde year & 3 se evalúa como int, pero los operadores lógicos AND (&&), OR (||) y NO (!) requieren bool argumentos.

+0

@tarabyte Muy amable. Gracias. Ahora, si podemos conseguir que Wikipedia publique un artículo mejor para el beneficio mundial ... –

+0

Entiendo el argumento de la eficiencia, pero ¿por qué etiquetas el algoritmo de Wikipedia como "poco confiable"? ¿En qué borde de caso falla? –

+4

@EricJ. Wikipedia no es confiable porque es editada constantemente por personas anónimas. He visto ediciones incorrectas del algoritmo. WP no es una fuente confiable de información, y a menudo está equivocada u orientada a la opinión. Debe verse como conversador, pero no canónico. –

1
 

    #include 
    void main(void) 
    { 
     int year; 
     printf("Enter a year to check if it is Leap Year\n"); 
     scanf("%d",&year); 
     if(year%400==0) /*  Why mod 400 */ 
      printf("%d is a Leap Year\n",year); 
     else if(year%100==0) /*  Why mod 100 */ 
      printf("%d is not a Leap Year\n",year); 
     else if(year%4==0) 
      printf("%d is a Leap Year\n",year); 
     else 
      printf("%d is not a Leap Year\n",year); 

    } 

3

Esta podría ser la solución correcta. Algoritmo dado en Wikipedia no es correcto.

-(BOOL)isLeapYear: (int)year{  

    if(year%4==0){ 
     if(year%100!=0){ 
     return YES; 
    } 
    else if(year%400!=0){ 
     return YES; 
    } 
    else return NO; 
    } 

    else return NO; 
    } 
0

Como otros también han mencionado la condición para año bisiesto no es correcta. Debe:

int yearr(int year) 
{ 
    if(((year%4 == 0) && (year%100 !=0)) || (year%400==0)) 
     return 1;  
    else  
     return 0;  
} 

Léelo aquí how to check leap year in C.

-5

#define is_leap(A) !((A) & 3)

Sólo asegúrese de que no introduce año negativo :)

+0

1900 no fue un año bisiesto. https://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar – jogo

+0

Ya han habido 11 respuestas anteriores y ofrecen una solución completa. Su solución ni siquiera se ocupa de algunos casos del año divisibles por 100 y 400. Por lo tanto, no es una respuesta y esto debería eliminarse. – phoenix

-1

Calcular max/último día de mes: 1..12, año: 1..3999

maxDays = month == 2 ? 
    28 + ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0)) : 
    30 + ((month & 1)^(month > 7)); 
+0

hm- alguien pierde el ingenioso truco por XOR'ing mes/mes OFFSET, difícilmente se puede encontrar en cualquier lugar. – user6801759

0

La respuesta de Kevin proporciona una prueba de operación 8 óptima (con XOR usando constantes) pero si buscas algo un poco más legible, prueba esta 9 prueba de funcionamiento.

year % 4 == 0 && !((year % 100 == 0)^(year % 400 == 0)) 

Tabla de verdad para (year % 100 == 0)^(year % 400 == 0)

       (year % 100 == 0)^(year % 400 == 0) 
100 doesnt divide year  . F 
only 100 divides year  . T 
100 and 400 divides year . F 

Ahora !(year % 100 == 0)^(year % 400 == 0) da lo que quieres.

+0

En realidad, uso bitwise-AND, no XOR. Además, reemplazo dos operaciones de módulo (división) con Y a nivel de bit. En muchos sistemas pequeños, la división requiere numerosas operaciones de CPU, por lo que los ahorros (en mi opinión) superan la ligera diferencia en la legibilidad. Además, para eso son los comentarios del código. –

1
I used this code: 

#include <stdio.h> 

int main() 
{ 
    int yr; 
    printf ("Enter a year \n"); 
    scanf ("%d", &yr); 

    if (yr%400 == 0) 
     printf("\n LEAP YEAR."); 

    else if (yr%4==0 && yr%100!=0) 
     printf("\n LEAP YEAR."); 
    else 
     printf ("\n NOT LEAP YEAR."); 
} 
Cuestiones relacionadas