Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: gaudenzi - Aprile 12, 2012, 01:34:53 am

Titolo: Variabili dichiarate come extended ma trattate come double
Inserito da: gaudenzi - Aprile 12, 2012, 01:34:53 am
Chiedo a qualcuno se può aiutarmi sul seguente problema.

La seguente funzione calcola il coefficiente binomiale c(n,k):

function c(n, k: integer): extended;
  var
   caux: extended;
   i: integer;
 begin
  caux := 1;
  if k > n - k then
   k := n - k;
  for i := n - k + 1 to n do
   caux := caux * i / (n + 1 - i);
  if k >= 0 then
   c := caux
  else
   c := 0;
 end;     

Le variabili sono dichiarate extended, ma il programma non riesce a calcolare c(1200,340) mentre calcola c(1200,336), la diffenenza è che il secondo valore è inferiore a 10^308 che è il range massimo delle variabili double, mentre il primo è superiore a tale limite. Ma il range massimo delle variabili extended è molto più alto: 10^4932, perchè il sistema usa variabili double mentre sono state dichiarate variabili extended?

Il programma si blocca generando il messaggio: Program raised exception class 'External:SIGFPE'

Grazie.
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: Microges2000 - Aprile 12, 2012, 07:56:56 am
Sinceramente me lo calcola corrrettamente comunque tieni presente che se devi lavorare con numeri molto grandi non usare variabili integer o comunque differenti da quella finale nel calcolo. Quindi puoi trasformare la tua routine cosi':

Codice: [Seleziona]
function c(n, k: integer): extended;
  var
   Var1, Var2, caux: extended;
   i: integer;
 begin
  caux := 1;
  if k > n - k then
   k := n - k;
  for i := n - k + 1 to n do
      Begin
        var1 := (n + 1 - i);
        Var2 := I;
        caux := caux * Var2 / Var1;

      end;
  if k >= 0 then
   c := caux
  else
   c := 0;
 end;
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: gaudenzi - Aprile 12, 2012, 09:49:39 am
Grazie per l'aiuto.
Anche nella versione proposta continua a generarmi un errore. Quindi sto usando qualcosa di diverso. Ricopio la parte iniziale del programma (prime delle procedure) per capire se la differenza sta nell'impostazione iniziale:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, Math,  SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, ComCtrls, types;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Image1: TImage;
    Memo1: TMemo;
    Memo2: TMemo;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    TabSheet3: TTabSheet;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

  type
  vettore=array[0..10000] of extended;
  vettoreint=array[0..10000] of integer;
  vettoredati=array[0..100] of extended;
  matrice=array[0..2000,0..2000] of extended;
  vettorelungod=array of extended;
var
  Form1: TForm1;
  DateTime1,DateTime2 : TDateTime;
  i,j:integer;
  x,y:vettore;
  cb:matrice;
  // variabili grafiche
  datox,datoy:vettore;
  numdati:integer;
  xmax,xmin,ymax,ymin:extended;
const
  px=1000;
  py=600;
  //xmax=10;
  //xmin=-2;
  //ymax=2;
  //ymin=-2;

implementation

{$R *.lfm}

{ TForm1 }
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: Microges2000 - Aprile 12, 2012, 11:35:05 am
Cavolo più di 39140.7 Kb di dati solo per le extended?!?!?!? Non ti pare un po' troppo? Manderebbe in tilt qualsiasi cosa comunque, dovresti ottimizzare
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: Fabio - Aprile 12, 2012, 02:00:15 pm
Non ti conviene usare array dinamici e poi semmai raggiunto un certo limite aumenti la dimensione di un altro po' con SetLenght ?
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: gaudenzi - Aprile 12, 2012, 02:07:09 pm
Si tratta di programmi di analisi numerica che coinvolgono array di 3 o 4 dimensioni e varie decine di procedure numeriche. Molto spesso utilizzo, se necessario, array dinamici dimensionati con Setlengh. Di solito lavoro ai limiti della disponibilità della memoria che ho a disposizione. Lavorando con Delphi 6 non ho avuto problemi a trattare programmi che utlizzavano decine di array tridimensionali in extended per un totale di quasi 2 giga di memoria. Ora sto passando a Lazarus per poter lavorare su Linux.
Comunque se riduco notevolmente la memoria richiesta il problema persiste, penso che si tratti di un problema di trattazione dei numeri di Lazarus, su Delphi 6 non ho problemi, i numeri sono effettivamenti trattati come extended anche nella procedura che avevo inserito all'inizio.
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: Microges2000 - Aprile 12, 2012, 03:57:46 pm
Che versione di Lazarus e freepascal usi?

Personalmente ho fatto le prove con:

Lazarus: 0.9.31
FPC: 2.7.1

e funziona correttamente
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: gaudenzi - Aprile 12, 2012, 05:01:10 pm
Attualmente ho lazarus 0.9.30.2, fpc 2.4.4  (\fpc\2.4.4\bin\x86_64-win64\fpc.exe, il computer è a 64 bit). Cercherò di aggiornare fpc alla versione 2.6.0, forse il problema dipende dal mancato aggiornamento.
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: gaudenzi - Aprile 12, 2012, 06:57:46 pm
Aggiornato a fpc 2.6.0 e Lazarus 0.9.30.4. Continua a non funzionare. Grazie comunque per l'aiuto.
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: Stilgar - Aprile 15, 2012, 10:08:55 pm
Scusate se mi intrometto (ho sempre odiato i virgola mobile ....)
Non è che per caso gli extended siano mappati come double?
Alla fine è un alias, da quello che leggo.

Dalla documentazione ufficile :http://www.freepascal.org/docs-html/prog/progsu144.html

Extended

For Intel 80x86 processors, the extended type has takes up 10 bytes of memory space. For more information on the extended type consult the Intel Programmer’s reference.

For all other processors which support floating point operations, the extended type is a nickname for the type which supports the most precision, this is usually the double type. On processors which do not support co-processor operations (and which have the {$E+} switch), the extended type usually maps to the single type.
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: gaudenzi - Aprile 19, 2012, 11:54:19 am
Problema risolto. Ho disinstallato la versione a 64 bit e sono passato a quella a 32 bit. Ora la trattazione delle variabili extended è corretta. Dunque è un problema della versione a 64 bit. Grazie a Microges2000, Fabio e Stilgar per la collaborazione.
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: doc - Marzo 30, 2021, 11:33:18 am
Riporto una nota dell'utente DragoRosso circa il tipo extended su sistemi x86 e x64.
" Ancorchè il tipo "extended" sia lecito, ma di fatto ne è assolutamente sconsigliato l'uso, occorre prestare molta attenzione al fatto che cambia la sua definizione tra un sistema a 32 e 64 bit. Nel x32 il tipo extended è di lunghezza 10 byte, mentre in x64 il tipo extended è di 8 byte e viene definito come un tipo double. Questa differenza ovviamente ha diversi aspetti impattanti: il primo e palese è la "risoluzione" cioè il numero di digit che il tipo può mantenere. Se è stato usato l'extended si suppone che serva per calcoli molto particolari di assoluta precisione, e tale pecularietà viene meno nel caso di passaggio da un codice 32 bit a 64 bit."

Quindi ecco il perchè ne passaggio da compilazione x64 a x86 il "problema" è scoparso.

Anche io mi occupo di calcolo numerico e molte volte, nella ricerca ossessionante della massima precisione possibile, mi dimentico dei limiti che i nostri strumenti hanno.
Ma è solo superando i nostri limiti che cresciamo.  ;)
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: nomorelogic - Marzo 31, 2021, 11:25:29 am
il topic è vecchio ma visto che siamo in argomento vorrei segnalare questo link

https://bugs.freepascal.org/view.php?id=34378 (https://bugs.freepascal.org/view.php?id=34378)

All'interno un commento di Florian
Citazione
The extended type is deprecated on win64 by MS, so it maps to double.
If you really know what you are doing, you can recompile the compiler with -dFPC_SUPPORT_X87_TYPES_ON_WIN64 to get it back, but you are at your own at this point.


Edit:
info dal mondo linux
ho lanciato il programmino di test scaricabile nel link sopra e l'ho lanciato sotto linux 64bit
non so sotto Win se le cose sono cambiate con gli extended, ma sotto linux l'extended è come ci si aspetta  ;)

Codice: [Seleziona]
SizeOf(Real)=8
SizeOf(Double)=8
SizeOf(Extended)=10, but has to be 10


Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: DragoRosso - Marzo 31, 2021, 09:52:11 pm
Non è un problema di sistema operativo, è un problema di come un processore x64 esegue il calcolo matematico quando si trova in ambiente x64.
Certo, puoi istruire il compilatore (penso che sia quello che fà), ad eseguire i calcoli con argomenti "extended" in un altro modo.

Occorre verificare però le prestazioni con quel flag "-dFPC_SUPPORT_X87_TYPES_ON_WIN64" attivo.

Come indicato,  il calcolo con dati extended non andrebbe usato.

Sotto Linux non sò come viene gestita la matematica, può essere che venga emulato il funzionamento originale dell'extended.

In ogni caso, è opportuno sempre verificare che i risultati siano comparabili:

1) faccio un calcolo in x86 in extended e mi annoto il risultato,
2) faccio il calcolo in x64  (in Windows, Linux, Mac, Android e chi più ne ha più ne metta), e verifico che i riusultati siano identici.

Mi è già capitato nel passato che un calcolo complesso in "double" venisse svolto in modalità "strane" e i risultati siano stati leggermente diversi.

Saluti
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: nomorelogic - Marzo 31, 2021, 10:16:29 pm
per quanto riguarda i float, in particolare, extended e real (almeno in fpc) la loro implementazione dipende dalla piattaforma target
è come un NativeInt che sarà a 32 o 64 bit a seconda del target

giusto per conoscenza, l'extended (come si legge alla fine di questo link), viene mappato al float più grande disponibile sulla piattaforma
https://wiki.freepascal.org/IEEE_754_formats (https://wiki.freepascal.org/IEEE_754_formats)

i risultati strani purtroppo capitano, e sono il risultato di quanto sopra abbinato ai cast impliciti all'interno di un calcolo
in effetti l'unico strumento che abbiamo è quello di verificare sempre e comunque (anche perché a volte non è affatto chiaro come mai non si ottenga il risultato esatto :) )
Titolo: Re:Variabili dichiarate come extended ma trattate come double
Inserito da: DragoRosso - Aprile 01, 2021, 12:14:13 am
Tutte le definizioni (chiamamole meglio convenzioni), come NativeInt o altre vengono usate, imposte o caldamente suggerite in base alle opportunità offerte dalle nuove tecnologie.

Chi, ad oggi, penserebbe di fare un calcolo intero a 64 bit come una serie di calcoli basate sulle vecchie istruzione x86 ?

Idem con patate le gestione ad esempio dei puntatori: limitarsi ad usare 2 GB (o giu di li) quando si ha a disposizione un mondo di GB (e quindi la necessità di avere puntatori "piu grandi") ?

Le istruzioni SIMD hanno surclassato, dal punto di vista prestazionale, le istruzioni FPU x87 e ciò ha praticamente mandato in disuso le FPU x87.

Si paga un costo, e abbastanza caro: come molti si ricorderanno i calcoli in FPU x87 venivano sempre svolti a 80 bit (extended appunto) e tutte i float venivano convertiti in extended e riconvertiti in float (single, double, real, ...).

Ciò portava ad avere una base di calcolo molto buona, dove tutti i calcoli venivano effettuati con una classe di precisione superiore al dato normalmente richiesto (per esempio double) e questo consentiva di avere un minore errore sulle approssimazioni (...... i puristi diranno che comunque si inserivano altri errori nelle conversioni).

Ora i calcoli vengono effettuati in double (quando và bene, perchè alcune volte questi potrebbero essere effettuati con precisione single), raramente a 128 bit o a 512 bit (anche perchè le unità di calcolo diponibili per queste precisioni estese sono comunque limitate).

Lo standard, come le convenzioni, sono opportunità. Il tipo extended (80 bit) viene definito, ma di fatto non viene (ne verrà) più usato perchè non è più la base "hardware" per la matematica "da PC".

Se invece parliamo di scienza o ricerca allora è diverso.

Chi conosce il campo della visione artificiale, sà che alle volte fare una serie di calcoli in single (magari ripetuti decine di migliaia di volte) conviene piuttosto che usare un double. Certo si perde in definizione, ma si guadagna in prestazioni e quindi anche la possibilità di usare ulteriori calcoli "per unità di tempo".

Saluti