AnteriorPosterior

7.9. Algunas funciones útiles: Números aleatorios, Funciones matemáticas

  Curso: Fundamentos de programación en C, por Nacho Cabanes

7.9. Algunas funciones útiles

7.9.1. Números aleatorios

En un programa de gestión o una utilidad que nos ayuda a administrar un sistema, no es habitual que podamos permitir que las cosas ocurran al azar. Pero los juegos se encuentran muchas veces entre los ejercicios de programación más completos, y para un juego sí suele ser conveniente que haya algo de azar, para que una partida no sea exactamente igual a la anterior.

Generar números al azar ("números aleatorios") usando C no es difícil. Si nos ceñimos al estándar ANSI C, tenemos una función llamada "rand()", que nos devuelve un número entero entre 0 y el valor más alto que pueda tener un número entero en nuestro sistema. Generalmente, nos interesarán números mucho más pequeños (por ejemplo, del 1 al 100), por lo que "recortaremos" usando la operación módulo ("%", el resto de la división).

Vamos a verlo con algún ejemplo:

Para obtener un número del 0 al 9 haríamos x = rand() % 10;
Para obtener un número del 0 al 29 haríamos x = rand() % 30;
Para obtener un número del 10 al 29 haríamos x = rand() % 20 + 10;
Para obtener un número del 1 al 100 haríamos x = rand() % 100 + 1;
Para obtener un número del 50 al 60 haríamos x = rand() % 11 + 50;
Para obtener un número del 101 al 199 haríamos x = rand() % 100 + 101;

Pero todavía nos queda un detalle para que los números aleatorios que obtengamos sean "razonables": los números que genera un ordenador no son realmente al azar, sino "pseudo-aleatorios", cada uno calculado a partir del siguiente. Podemos elegir cual queremos que sea el primer número de esa serie (la "semilla"), pero si usamos uno prefijado, los números que se generarán serán siempre los mismos. Por eso, será conveniente que el primer número se base en el reloj interno del ordenador: como es casi imposible que el programa se ponga en marcha dos días exactamente a la misma hora (incluyendo milésimas de segundo), la serie de números al azar que obtengamos será distinta cada vez.

La "semilla" la indicamos con "srand", y si queremos basarnos en el reloj interno del ordenador, lo que haremos será srand(time(0)); antes de hacer ninguna llamada a "rand()".

Para usar "rand()" y "srand()", deberíamos añadir otro fichero a nuestra lista de "includes", el llamado "stdlib":

#include <stdlib.h>

Si además queremos que la semilla se tome a partir del reloj interno del ordenador (que es lo más razonable), deberemos incluir también "time":

#include <time.h>

Vamos a ver un ejemplo, que muestre en pantalla un número al azar entre 1 y 10:

/*---------------------------*/
/*  Ejemplo en C nº 69:      */
/*  C069.C                   */
/*                           */
/*  Obtener un número al     */
/*  azar                     */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/
 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
int main() {
    int n;
    srand(time(0));
    n = rand() % 10 + 1;
    printf("Un número entre 1 y 10: %d\n", n);
 
    return 0;
}
 

Ejercicios propuestos:

ul>
  • Crea un programa que escriba varias veces "Hola" (entre 5 y 10 veces, al azar).
  • Crear un programa que genere un número al azar entre 1 y 100. El usuario tendrá 6 oportunidades para acertarlo.
  • Crea un programa que muestre un "fondo estrellado" en pantalla: mostrará 24 líneas, cada una de las cuales contendrá entre 1 y 78 espacios (al azar) seguidos por un asterisco ("*").
  • 7.9.2. Funciones matemáticas

    Dentro del fichero de cabecera "math.h" tenemos acceso a muchas funciones matemáticas predefinidas en C, como:

    • acos(x): Arco coseno
    • asin(x): Arco seno$
    • atan(x): Arco tangente
    • atan2(y,x): Arco tangente de y/x (por si x o y son 0)
    • ceil(x): El valor entero superior a x y más cercano a él
    • cos(x): Coseno
    • cosh(x): Coseno hiperbólico
    • exp(x): Exponencial de x (e elevado a x)
    • fabs(x): Valor absoluto
    • floor(x): El mayor valor entero que es menor que x
    • fmod(x,y): Resto de la división x/y
    • log(x): Logaritmo natural (o neperiano, en base "e")
    • log10(x): Logaritmo en base 10
    • pow(x,y): x elevado a y
    • sin(x): Seno
    • sinh(x): Seno hiperbólico
    • sqrt(x): Raíz cuadrada
    • tan(x): Tangente
    • tanh(x): Tangente hiperbólica

      (todos ellos usan parámetros X e Y de tipo "double")

      y una serie de constantes como

      M_E, el número "e", con un valor de 2.71828...
      M_PI, el número "Pi", 3.14159...

      La mayoría de ellas son específicas para ciertos problemas matemáticos, especialmente si interviene la trigonometría o si hay que usar logaritmos o exponenciales. Pero vamos a destacar las que sí pueden resultar útiles en situaciones más variadas:

    La raiz cuadrada de 4 se calcularía haciendo x = sqrt(4);
    La potencia: para elevar 2 al cubo haríamos y = pow(2, 3);
    El valor absoluto: si queremos trabajar sólo con números positivos usaríamos n = fabs(x);

    Ejercicios propuestos:

    • Crear un programa que halle cualquier raíz de un número. El usuario deberá indicar el número (por ejemplo, 2) y el índice de la raiz (por ejemplo, 3 para la raíz cúbica). Pista: hallar la raíz cúbica de 2 es lo mismo que elevar 2 a 1/3.
    • Crear un programa que resuelva ecuaciones de segundo grado, del tipo ax2 + bx + c = 0 El usuario deberá introducir los valores de a, b y c. Pista: la solución se calcula con
      x = +- raíz (b2 – 4·a·c) / 2·a
    • Crear un programa que muestre el seno de los ángulos de 30 grados, 45 grados, 60 grados y 90 grados. Cuidado: la función "sin" espera que se le indique el ángulo en radianes, no en grados. Tendrás que recordar que 180 grados es lo mismo que Pi radianes (con Pi = 3,1415926535). Puedes crearte una función auxiliar que convierta de grados a radianes.

    7.9.3. Pero casi todo son funciones…

    Pero en C hay muchas más funciones de lo que parece. De hecho, casi todo lo que hasta ahora hemos llamado "órdenes", son realmente "funciones", y la mayoría de ellas incluso devuelven algún valor, que hasta ahora habíamos despreciado en muchos casos.

    Vamos a hacer un repaso rápido a las funciones que ya conocemos y el valor que devuelven:

    td width="108" valign="top">

    int

    Función

    Valor devuelto

    Significado

    main

    int

    Programa terminado correctamente (0) o no (otro)

    printf

    Número de caracteres escritos

    scanf

    int

    Número de datos leídos, o EOF si hay error

    putchar

    int

    El carácter escrito, o EOF si hay algún error

    getchar

    int

    Siguiente carácter de la entrada, o EOF en caso de error

    gets

    char*

    Cadena si todo va bien o NULL si hay error

    puts

    int

    EOF si hay algún error, otro número (un entero positivo) si no lo hay

    strcpy, strncpy

    char*

    Cadena resultado de la asignación

    strcat

    char*

    Cadena resultado

    strcmp

    int

    0 si las cadenas son iguales, <0 si la primera ?es menor? o >0 si la primera ?es mayor?

    sprintf

    int

    Número de caracteres almacenados en la cadena (en alguna versión, como BSD, devuelve la cadena creada)

    sscanf

    int

    Número de datos leídos, o EOF si hay error

    fopen

    FILE*

    NULL si hay error

    fclose

    int

    0 si todo va bien o EOF si hay error

    fputs

    int

    EOF si hay algún error, otro número (no especificado) si no lo hay

    fgets

    char*

    NULL si hay error o fin de fichero

    feof

    int

    0 si no es final de fichero, otro valor si lo es

    fprintf

    int

    Número de bytes escritos (puede no ser fiable si se está escribiendo a un buffer antes de mandar a disco).

    fscanf

    int

    Número de datos leídos, o EOF si hay error

    fgetc

    int

    El carácter leido, o EOF si hay algún error

    fputc

    int

    El carácter escrito, o EOF si hay algún error

    fread

    int

    Número de bytes leidos (0 o menor de lo previsto si hay error)

    fwrite

    int

    Número de bytes escritos (0 o menor de lo previsto si hay error)

    fseek

    int

    0 si se ha saltado correctamente; otro valor si el fichero no está abierto o no se ha podido saltar

    ftell

    long (size_t)

    Posición actual en el fichero (en bytes) o -1L en caso de error

     

     

    (Nota: expresiones como "FILE*" ya las conocemos, aunque todavía no entendemos bien a qué se refieren: otras como "char*" son nuevas para nosotros, pero las veremos con detalle en el próximo tema).

    Por el contrario, las siguientes "órdenes" no son funciones, sino "palabras reservadas" del lenguaje C: if, else, do, while, for, switch, case, default, break, int, char, float, double, struct.

    Ejercicios propuestos:

    • Crea un programa que escriba la raíz cuadrada de 10 y muestre la cantidad de cifras que se han escrito en pantalla. (Pista: mira el valor devuelto por "printf").

    Actualizado el: 25-07-2014 17:13

    AnteriorPosterior