Cómo imprimir un número entero en cualquier base

Accidentalmente descubrí algo que ya muchos deben saber:


Serial.print(numero,base);

Esta instrucción imprime un número entero en la base especificada. Si base=1 el número se imprime en decimal.

Si base tiene decimales, se truncan. Como se acostumbra hacer, si el número es tipo float se imprime en decimal y base representará el número de posiciones decimales a imprimir.

Por ejemplo,

Serial.print(100,1); // ==> 100
Serial.print(100,2); // ==> 1100100 BIN
Serial.print(100,3); // ==> 10201
Serial.print(100,4); // ==> 1210
Serial.print(100,5); // ==> 400
Serial.print(100,6); // ==> 244
Serial.print(100,7); // ==> 202
Serial.print(100,8); // ==> 144
Serial.print(100,9); // ==> 121
Serial.print(100,10); // ==> 100 DEC
Serial.print(100,11); // ==> 91
Serial.print(100,12); // ==> 84
Serial.print(100,13); // ==> 79
Serial.print(100,14); // ==> 72
Serial.print(100,15); // ==> 6A
Serial.print(100,16); // ==> 64 HEX

En aquellos días yo usaba base 2 (binario). Me inicié con una mainframe CDC 6600 (o era 6700?) que tenía una longitud de palabra de 60 bits y el "lenguaje" era base 8 (octal). Cuando aparecieron los microprocesadores fue que empecé a usar base 16 (hexadecimal).

Solamente he usado base 5 para algo práctico, y me sirvió bastante. Los demás casos, como curiosidad.

Si, está en la Guía de referencia

De todos modos, se agradece.

Saludos

1 Like

He hecho pruebas en Arduino Uno (genuino), Mega2560 (IEK) y Arduino Nano ("genérico", con Old Bootloader), y en los tres la función print() imprime correctamente enteros en las bases 1 a 20

Es interesante cómo la documentación no es muy clara y no está completa. En este caso, la funcionalidad de Serial.println(int, int) solamente viene en Inglés y está muy escueta y algo oculta en la documentación de referencia que menciona @anon90500195.

En Mac encontramos Print.cpp en la ruta

/Applications/Arduino 1.8.19.app/Contents/Java/hardware/arduino/avr/cores/arduino/

con la siguiente funcionalidad:

// Public Methods //////////////////////////////////////////////////////////////

...

size_t Print::print(long n, int base)
{
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
      return printNumber(n, 10) + t;
    }
    return printNumber(n, 10);
  } else {
    return printNumber(n, base);
  }
}

...

// Private Methods /////////////////////////////////////////////////////////////

...

size_t Print::printNumber(unsigned long n, uint8_t base)
{
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    char c = n % base;
    n /= base;

    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

  return write(str);
}

de manera que efectivamente la función print(long, int) está diseñada para imprimir enteros en cualquier base > 0.

Ahí se puede ver que función Print devuelve el número de caracteres impresos, lo cual puede servir para espaciar la impresión


Por otro lado, encontré que bitRead() y similares son macros, y hay una macro que no aparece en la documentación: bitToggle()

Tomado de Arduino.h:

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))

Ya la probé y funciona como se espera...

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.