Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Generic Integer zu Float konvertieren (https://www.delphipraxis.net/194694-generic-integer-zu-float-konvertieren.html)

Zacherl 22. Dez 2017 13:04

Delphi-Version: 10 Berlin

Generic Integer zu Float konvertieren
 
Hallo zusammen,

ich habe einen generischen Record der Form
Delphi-Quellcode:
type TMyRec<T: record>
mit den Spezialisierungen
Delphi-Quellcode:
type TMyURec = TMyRec<UInt8/Uint16/UInt32>
und
Delphi-Quellcode:
type TMyIRec = TMyRec<Int8/int16/Int32>
. Ich möchte nun eine implizite Konvertierung vom generischen Typ zu Single/Double implementieren.

Gibt es hier eine elegante Möglichkeit, ohne den konkreten generischen Typ zu ermitteln? Einfach alles in den größtmöglichen Integer Typen zu kopieren und dann zu konvertieren ist leider keine Möglichkeit, da ich wissen muss, wie das Vorzeichen zu behandeln ist.

Momentan tendiere ich dazu einfach zwei "Basis-Records" zu definieren; Einen für unsigned und Einen für signed. Das bedeutet allerdings einiges an dupliziertem Code.

Viele Grüße
Zacherl

TiGü 22. Dez 2017 13:18

AW: Generic Integer zu Float konvertieren
 
Zitat:

Zitat von Zacherl (Beitrag 1389493)

Gibt es hier eine elegante Möglichkeit, ohne den konkreten generischen Typ zu ermitteln? Einfach alles in den größtmöglichen Integer Typen zu kopieren und dann zu konvertieren ist leider keine Möglichkeit, da ich wissen muss, wie das Vorzeichen zu behandeln ist.

Tuts da nicht trotzdem ein record -> Int64 -> Double?
Vorzeichen bleiben erhalten und alles ist gut?!

Oder kommst an den Wert des Record mit High und Low ran?
Dann könntest du im Falle das Low(DeinRecord.Value) < 0 entsprechen agieren.

Delphi-Quellcode:
var
  x1: UInt16;
  x2: Int16;
begin
  Writeln(High(x1));
  Writeln(Low(x1));
  Writeln(High(x2));
  Writeln(Low(x2));
  Readln;
end.

Stevie 22. Dez 2017 13:25

AW: Generic Integer zu Float konvertieren
 
Delphi-Quellcode:
function TMyRec<T>.ToDouble: Double;
begin
  case GetTypeData(TypeInfo(t)).OrdType of
    otSByte: Result := PShortInt(@v)^;
    otUByte: Result := PByte(@v)^;
    otSWord: Result := PSmallInt(@v)^;
    otUWord: Result := PByte(@v)^;
    otSLong: Result := PInteger(@v)^;
    otULong: Result := PCardinal(@v)^;
  end;
end;
Edit: Das soll natürlich PWord sein bei otUWord :mrgreen:

Zacherl 22. Dez 2017 13:31

AW: Generic Integer zu Float konvertieren
 
Zitat:

Zitat von TiGü (Beitrag 1389495)
Tuts da nicht trotzdem ein record -> Int64 -> Double?

Habe die 64-bit Typen in meinem Originalpost vergessen :stupid: Da würde es dann leider nicht funktionieren.

Zitat:

Zitat von Stevie (Beitrag 1389497)
Delphi-Quellcode:
function TMyRec<T>.ToDouble: Double;
begin
  case GetTypeData(TypeInfo(t)).OrdType of
    otSByte: Result := PShortInt(@v)^;
    otUByte: Result := PByte(@v)^;
    otSWord: Result := PSmallInt(@v)^;
    otUWord: Result := PByte(@v)^;
    otSLong: Result := PInteger(@v)^;
    otULong: Result := PCardinal(@v)^;
  end;
end;

Das wäre von der Idee her perfekt, aber ist das intrinsisch, oder erzeugt das Runtime-Overhead?

Stevie 22. Dez 2017 13:40

AW: Generic Integer zu Float konvertieren
 
Zitat:

Zitat von Zacherl (Beitrag 1389499)
Zitat:

Zitat von Stevie (Beitrag 1389497)
Delphi-Quellcode:
function TMyRec<T>.ToDouble: Double;
begin
  case GetTypeData(TypeInfo(t)).OrdType of
    otSByte: Result := PShortInt(@v)^;
    otUByte: Result := PByte(@v)^;
    otSWord: Result := PSmallInt(@v)^;
    otUWord: Result := PByte(@v)^;
    otSLong: Result := PInteger(@v)^;
    otULong: Result := PCardinal(@v)^;
  end;
end;

Das wäre von der Idee her perfekt, aber ist das intrinsisch, oder erzeugt das Runtime-Overhead?

Leider bisschen runtime overhead.
Wenn du genau weißt, dass dein T nur von den 6 System Typen ist und nicht von irgendwelchen Redeklarationen a la
Delphi-Quellcode:
type TColumnIndex = type Integer
dann kannst du auch das hier schreiben - TypeInfo vergleiche werden seit XE7 zur Compilezeit aufgelöst (kannst auch beides kombinieren so, dass du schnell bist, wenns Integer, Byte etc ist und wenn nicht auf die langsamere Variante zurück fällst)

Delphi-Quellcode:
function TMyRec<T>.ToDouble: Double;
begin
  if TypeInfo(T) = TypeInfo(ShortInt) then
    Result := PShortInt(@v)^
  else if TypeInfo(T) = TypeInfo(Byte) then
    Result := PByte(@v)^
  else if TypeInfo(T) = TypeInfo(SmallInt) then
    Result := PSmallInt(@v)^
  else if TypeInfo(T) = TypeInfo(Word) then
    Result := PWord(@v)^
  else if TypeInfo(T) = TypeInfo(Integer) then
    Result := PInteger(@v)^
  else if TypeInfo(T) = TypeInfo(Cardinal) then
    Result := PCardinal(@v)^
  else if TypeInfo(T) = TypeInfo(UInt64) then
    Result := PUInt64(@v)^
  else if TypeInfo(T) = TypeInfo(Int64) then
    Result := PInt64(@v)^
  else
    case GetTypeKind(T) of
      tkInteger:
        case GetTypeData(TypeInfo(t)).OrdType of
          otSByte: Result := PShortInt(@v)^;
          otUByte: Result := PByte(@v)^;
          otSWord: Result := PSmallInt(@v)^;
          otUWord: Result := PWord(@v)^;
          otSLong: Result := PInteger(@v)^;
          otULong: Result := PCardinal(@v)^;
        end;
      tkInt64:
        if GetTypeData(TypeInfo(T)).MinInt64Value = 0 then
          Result := PUInt64(@v)^
        else
          Result := PInt64(@v)^;
    end;
end;

TiGü 22. Dez 2017 13:56

AW: Generic Integer zu Float konvertieren
 
Zitat:

Zitat von Zacherl (Beitrag 1389499)
Zitat:

Zitat von TiGü (Beitrag 1389495)
Tuts da nicht trotzdem ein record -> Int64 -> Double?

Habe die 64-bit Typen in meinem Originalpost vergessen :stupid: Da würde es dann leider nicht funktionieren.

Nehme doch einen Int128! :idea:

Spaß beiseite, das muss doch elegant auch mit Low(deinRecord.Value) < 0 gehen (falls meine zweite Idee im Post untergegangen ist)!

Stevie 22. Dez 2017 13:58

AW: Generic Integer zu Float konvertieren
 
Zitat:

Zitat von TiGü (Beitrag 1389503)
Zitat:

Zitat von Zacherl (Beitrag 1389499)
Zitat:

Zitat von TiGü (Beitrag 1389495)
Tuts da nicht trotzdem ein record -> Int64 -> Double?

Habe die 64-bit Typen in meinem Originalpost vergessen :stupid: Da würde es dann leider nicht funktionieren.

Nehme doch einen Int128! :idea:

Spaß beiseite, das muss doch elegant auch mit Low(deinRecord.Value) < 0 gehen (falls meine zweite Idee im Post untergegangen ist)!

Er will doch die Konvertierung in den Record einbauen, und Low auf T geht nunmal nicht.
In Delphi generics geht leider das meiste nicht elegant, weils nunmal keine C++ Templates sind, denen das herzlich egal wäre,
wenn aus der Menge aller im Universum möglichen Typen für T welche nicht mit Ord funktionieren, solang du nur solche nutzt, bei denen das geht.

TiGü 22. Dez 2017 14:20

AW: Generic Integer zu Float konvertieren
 
Zitat:

Zitat von Stevie (Beitrag 1389504)
Er will doch die Konvertierung in den Record einbauen, und Low auf T geht nunmal nicht.

Ich hab das "implizite Konvertierung" überlesen. :oops:

Zacherl 22. Dez 2017 14:28

AW: Generic Integer zu Float konvertieren
 
Danke euch beiden :thumb:

Ich werde dann wahrscheinlich mal mit Stevies zweiter Variante probieren :)

Zitat:

Zitat von Stevie (Beitrag 1389504)
In Delphi generics geht leider das meiste nicht elegant, weils nunmal keine C++ Templates sind, denen das herzlich egal wäre

Die C++ Templates sind tatsächlich das, was ich unter Delphi tatsächlich am meisten vermisse.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:09 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz