Reputation: 575
I have used this code to split into parts
however I now need to handle floats.
eg. 101.01
type TSplitNumber = record
Hundreds : integer
Tens : integer
Ones : integer
DecimalPl1 : integer //this will contain 0
DecimalPl2 : integer //this will contain 1
DecimalPl3 : integer
end;
Heres is implementation so far but it only handles non-floats.
type TDivisions = record
Hundreds : integer;
Tens : integer;
Ones : integer;
end;
function SplitNumberIntoDivisions(number : integer) : TDivisions;
var
p : integer;
Ones : integer;
Tens : integer;
Hundreds : integer;
MyDivision : TDivisions;
begin
p := 1;
while number <> 0 do
begin
if p = 1 then
begin
MyDivision.Ones := (number mod 10);
number := number div 10;
Inc(p);
end;
if p = 2 then
begin
MyDivision.Tens := (number mod 10);
number := number div 10;
Inc(p);
end;
if p = 3 then
begin
MyDivision.Hundreds := (number mod 10);
number := number div 10;
Inc(p);
end;
Result := MyDivision;
end;
end;
Anyone got any idea on how to do this?
Ben
Upvotes: 2
Views: 664
Reputation: 2293
First of all, recognise what your float
is. Depending on the architecture you will have a certain number of significant digits. Upto 15 is typical but certain architectures may (at some point) give you more, and BCD as implemented in the RTL will give you up to 64.
You then have a 'power' indicating where the decimal point is. Typically you refer to the parts of the float
as the mantissa and exponent.
So your answer is going to comprise a set of dgits, each digit being a power of 10, where the powers of 10 are all consecutive and may be all >0 or all <0 or they could straddle 0.
So you will need a structure to hold your powers of 10 which could be something like:
type TDecimalFactor = class(TObject)
Digit: Integer;
Power: Integer;
end;
You can find out what your largest power of 10 is by taking the base 10 log of the number. (So log(100) is 2 and log(1000) is 3 and log(0.1) is -1).
I suggest it would probably be fairly straightforward to 'normalise' your number by dividing it by the highest power - so you have a number which is between 1 and 9.999999999999999 and you know the power it represents. Then work through the number for a many digits as you want (bearing in mind the resolution of the platform) multiplying the float by 10 each time and decrementing your power by 1.
Sample program for you to play with:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Math, System.Generics.Collections;
type
TDecimalFactor = class(TObject)
protected
_nDigit: Integer;
_nPower: Integer;
function _GetValue(): Double;
public
constructor Create(nDigit, nPower: Integer);
procedure ShowFactor();
property Digit: Integer read _nDigit;
property Power: Integer read _nPower;
property Value: Double read _GetValue;
end;
TDecimalFactors = class(TObjectList<TDecimalFactor>)
protected
function _GetValue(): Double;
public
property Value: Double read _GetValue;
end;
constructor TDecimalFactor.Create(nDigit, nPower: Integer);
begin
Self._nDigit:=nDigit;
Self._nPower:=nPower;
inherited Create();
end;
function TDecimalFactor._GetValue(): Double;
begin
Result:=Self._nDigit*System.Math.Power(10, Self._nPower);
end;
procedure TDecimalFactor.ShowFactor();
begin
writeln('Factor: ', IntToStr(Self._nDigit), ' x ', FloatToStr(System.Math.Power( 10, Self._nPower)));
end;
function TDecimalFactors._GetValue(): Double;
var
pFactor: TDecimalFactor;
begin
Result:=0;
for pFactor in Self do
Result:=Result+pFactor.Value;
end;
var
fValue: Double;
fLog: Double;
nPower: Integer;
fPower: Double;
nDigits: Integer;
nLoop: Integer;
pDigits: TDecimalFactors;
pFactor: TDecimalFactor;
begin
try
pDigits:=TDecimalFactors.Create(true);
fValue:=6.5788902E-5; // try different values here to test operation
writeln('Input Value: '+FloatToStr(fValue));
nDigits:=15;
fLog:=log10(fValue);
nPower:=floor(fLog);
fPower:=Power(10,nPower);
fValue:=fValue/fPower;
nLoop:=0;
while(nLoop<nDigits) do
begin
pFactor:=TDecimalFactor.Create(floor(fValue), nPower);
pDigits.Add(pFactor);
pFactor.ShowFactor();
fValue:=(fValue-pFactor.Digit)*10;
inc(nLoop);
dec(nPower);
// stop the loop when we have got far enough, recognising limited precision
if(SameValue(fValue, 0, 0.00000001)) then
break;
end;
writeln('Factorised Value: '+FloatToStr(pDigits.Value));
FreeAndNil(pDigits);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Upvotes: 1