Quoto appieno
Oregon. Come validamente
accennato qui, i limiti dei tipi numerici dipendono strettamente dal compilatore, anche in funzione dall'architettura target. L'articolo cita inoltre le principali librerie gratuite per aritmetica intera a precisione arbitraria.
Comunque il reale problema consiste unicamente nella scelta dell'algoritmo e nell'impostazione dell'esercizio, tutto il resto è decisamente secondario.
PHP è l'ultima cosa a cui pensare : semmai in Python la gestione trasparente di tipi numerici interi di dimensione arbitraria è una validissima alternativa, molto ben implementata e ragionevolmente efficiente, considerando la natura del linguaggio.
Riporto per l'ennesima volta un sorgente didattico, utile a determinare rapidamente gli intervalli numerici supportati dai compilatori mainstream più diffusi.
/************************************************************************/
/** Visualizza i limiti di campo per i tipi numerici di default. **/
/** Include la gestione dei tipi a 64 bit. **/
/** Adatto ai seguenti compilatori: **/
/** - Intel C/C++ **/
/** - Borland C/C++ **/
/** - Microsoft Visual C/C++ **/
/** - Digital Mars **/
/** - Open Watcom **/
/** - GCC e derivati **/
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "int64bit.h"
#define BUFF_SIZE 64
#define H_SEP_STAR "************************************************************"
#define H_SEP_LINE "------------------------------------------------------------"
/*
** Inserisce i separatori di migliaia (europei) in una stringa numerica.
*/
char *numfmt(const char *in, char *out)
{
int p = 0;
int size = strlen(in) * 4 / 3;
memset(out, ' ', size);
out += size +1;
*out-- = '\0';
in += strlen(in) -1;
do
{
if ((p > 0) && (0 == (p % 3)))
{
*out-- = '.';
}
*out-- = *in--;
++p;
} while (isdigit(*in) || ('-' == *in));
return ++out;
}
/************************************************************************/
int main(void)
{
char num_buff[BUFF_SIZE+1];
char fmt_buff[BUFF_SIZE+1];
printf("\n%s\n%s\n%s\n", H_SEP_STAR, Compiler, H_SEP_STAR);
printf("- UNSIGNED:\n"
"char...........: [0, %u] (%d bits per char)\n",
UCHAR_MAX, CHAR_BIT);
snprintf(num_buff, BUFF_SIZE, "%u", USHRT_MAX);
printf("short int......: [0, %s]\n", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%lu", UINT_MAX);
printf("int............: [0, %s]\n", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%lu", ULONG_MAX);
printf("long int.......: [0, %s]\n", numfmt(num_buff, fmt_buff));
/* Forma alternativa, valida per vari compilatori Windows legacy:
#if defined(_UI64_MAX)
_ui64toa(_UI64_MAX, num_buff, 10);
printf("long int 64....: [0, %s]\n", numfmt(num_buff, fmt_buff));
#endif
*/
#if defined(UINT64_MAX)
snprintf(num_buff, BUFF_SIZE, "%"PRIu64, UINT64_MAX);
printf("long int 64....: [0, %s]\n", numfmt(num_buff, fmt_buff));
#endif
puts(H_SEP_LINE);
printf("- SIGNED:\n"
"char...........: [%d, %d]\n", SCHAR_MIN, SCHAR_MAX);
snprintf(num_buff, BUFF_SIZE, "%d", SHRT_MIN);
printf("short int......: [%s", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%d", SHRT_MAX);
printf(", %s]\n", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%d", INT_MIN);
printf("int............: [%s", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%d", INT_MAX);
printf(", %s]\n", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%d", LONG_MIN);
printf("long int.......: [%s", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%ld", LONG_MAX);
printf(", %s]\n", numfmt(num_buff, fmt_buff));
#if defined(INT64_MAX)
snprintf(num_buff, BUFF_SIZE, "%"PRId64, INT64_MIN);
printf("long int 64....: [%s,\n", numfmt(num_buff, fmt_buff));
snprintf(num_buff, BUFF_SIZE, "%"PRId64, INT64_MAX);
printf(" %s]\n", numfmt(num_buff, fmt_buff));
#endif
/************************************************************************/
puts(H_SEP_STAR);
puts("- FP IEEE 754:");
printf("float..........: [%g, %g]\n", FLT_MIN, FLT_MAX);
printf("double.........: [%g, %g]\n", DBL_MIN, DBL_MAX);
printf("long double....: [%Lg, %Lg]\n", LDBL_MIN, LDBL_MAX);
puts(H_SEP_LINE);
printf("FLT_EPSILON....: %g\n", FLT_EPSILON);
printf("DBL_EPSILON....: %g\n", DBL_EPSILON);
printf("LDBL_EPSILON...: %Lg\n", LDBL_EPSILON);
puts(H_SEP_STAR);
return 0;
}
/* EOF: TestLim.c */
Lo header file associato:
#ifndef __INT64BIT_H__
#define __INT64BIT_H__
#include <limits.h>
#include <float.h>
#if defined(__BORLANDC__)
const char Compiler[] = "** Compiled with Borland C++"
" **";
#if __BORLANDC__ >= 1400
#include <stdint.h>
#elif defined(_UI64_MAX)
/* __BORLANDC__ >= 0x400 */
typedef unsigned __int64 uint64_t;
#define UINT64_MAX _UI64_MAX
#define INT64_MAX _I64_MAX
#define INT64_MIN _I64_MIN
#endif
#ifndef PRIu64
#define PRIu64 "I64u"
#define PRId64 "I64d"
#endif
#endif
#if defined(_MSC_VER)
const char Compiler[] = "** Compiled with Visual C/C++"
" **";
#if _MSC_VER > 1500
#include <stdint.h>
#elif defined(_UI64_MAX)
/* _MSC_VER >= 900 */
typedef unsigned __int64 uint64_t;
#define UINT64_MAX _UI64_MAX
#define INT64_MAX _I64_MAX
#define INT64_MIN _I64_MIN
#endif
#ifndef PRIu64
#define PRIu64 "I64u"
#define PRId64 "I64d"
#endif
#endif
#if defined(__WATCOMC__)
const char Compiler[] = "** Compiled with Open Watcom"
" **";
#include <inttypes.h>
#endif
#if defined(__DMC__)
const char Compiler[] = "** Compiled with Digital Mars"
" **";
#include <inttypes.h>
#endif
#if defined(__INTEL_COMPILER)
const char Compiler[] = "** Compiled with INTEL C "
" **";
#include <inttypes.h>
#endif
#if defined(__GNUC__)
const char Compiler[] = "** Compiled with GCC "
" **";
#include <inttypes.h>
#endif
#endif /* __INT64BIT_H__ */
/* EOF: int64bit.h */