Jump to content
Sign in to follow this  
Darian Miller

Double-dabble to convert binary to decimal

Recommended Posts

I imagine one of the biggest problems of being self-taught is missing out on some well-documented practices.  Well, I confess that I did not know about the use of double-dabble to quickly manually convert a base-2 representation to base-10, for example: 1001000110 to 582.  Quick blog post published today:

https://www.ideasawakened.com/post/double-dabble-and-conversions-from-base-10-and-base-2-number-systems

 

 

  • Like 2

Share this post


Link to post

Hm, I always convert to hex as an intermediary step (and actually prefer hex constants in source code). and I can still do binary to hex and back in my head, back from the C64 times.

  • Like 1

Share this post


Link to post
Guest

I have mountain of things that need to be done right now, but what to say !, i am bored to hell and looking something to do away from what is needed, so.

 

@Darian Miller this is special for you 

program BinaryNumbers;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

function IntToBin(Value: Integer; Digits: Integer = 0): string;
var
  I, Len: Integer;
  Negative: Boolean;
begin
  // Set boundaries and limits
  Negative := Value < 0;
  if Negative then
    Value := 0 - Value;
  Len := 1;
  while (1 shl Len) <= Value do
    Len := Len + 1;
  if Digits < 1 then
    Digits := 1
  else if Digits > 31 then
    Digits := 31;
  if Len < Digits then
    Len := Digits;
  Len := Len + Ord(Negative);

  // Do translate
  SetLength(Result, Len);
  I := 0;
  while Value > 0 do
  begin
    Result[Len - I] := Char((Value and 1) + Ord('0'));
    Value := Value shr 1;
    Inc(I);
  end;

  // Fill leading zeroes, up to Digits, and add signal
  while I < Digits do
  begin
    Result[Len - I] := '0';
    Inc(I);
  end;
  if Negative then
    Result[1] := '-';
end;

function DoubleToBin(Value: Double; Digits: Integer = 0; FracDigits: Integer = 8): string;
var
  I, Len: Integer;
  IntPart: Integer;
  FractalPart: Double;
begin
  IntPart := Trunc(Value);
  Result := IntToBin(IntPart, Digits);

  // Prepare result for fractal part
  FractalPart := Value - IntPart;
  if FractalPart < 0 then
    FractalPart := 0 - FractalPart;
  if (FracDigits > 0) or (FractalPart > 0) then
    Result := Result + '.';

  // Set boundaries and limits for fractal part
  Len := 0;
  if FracDigits < 0 then
    FracDigits := 0;
  if Len < FracDigits then
    Len := FracDigits;
  if Len = 0 then
    Exit;

  // Do translate
  I := Length(Result);
  SetLength(Result, I + Len);
  Inc(FracDigits, I);
  while (FractalPart > 0) and (I < FracDigits) do
  begin
    FractalPart := FractalPart * 2;
    Inc(I);
    Result[I] := Char(Ord(FractalPart >= 1) + Ord('0'));
    if FractalPart >= 1 then
      FractalPart := FractalPart - 1;
  end;

  // Fill trailing zeroes, up to FracDigits
  while (I < FracDigits) do
  begin
    Inc(I);
    Result[I] := '0';
  end;
end;

function BinaryToInt(const Value: string): Integer;

  procedure NotValidOfIntegerException;
  begin
    raise Exception.Create('BinaryToInt Error : ''' + Value + ''' is not valid binary integer');
  end;

var
  I, S, Len: Integer;
  Negative: Boolean;
begin
  //  Check validity and set boundaries
  Result := 0;
  Len := Length(Value);
  if Len = 0 then
    Exit;
  Negative := Value[1] = '-';
  if Negative then
  begin
    if Len = 1 then
      NotValidOfIntegerException;
    S := 2;
  end
  else
    S := 1;
  for I := S to Len do
    if (Value[I] <> '0') and (Value[I] <> '1') then
      NotValidOfIntegerException;

  // calculate
  for I := S to Len do
    Result := Result + (Ord(Value[I]) - Ord('0')) shl (Len - I);
  if Negative then
    Result := 0 - Result;
end;

//  simple and naive conversion function, though the fractal part is OK with the standard
//  not IEEE X compatible as the integer part is considered as simple integer
//  in IEEE standards the integral part should be exponentially calculated and not converted into decimal
function BinaryToDouble(const Value: string): Double;

  procedure NotValidBinaryOfDoubleException;
  begin
    raise Exception.Create('BinaryToDouble Error : ''' + Value + ''' is not valid binary double');
  end;

var
  I, P, Len: Integer;
  IntPart: string;
  Temp: Double;
begin
  //  Check validity and set boundaries
  Result := 0;
  Len := Length(Value);
  if Len = 0 then
    Exit;
  P := Pos('.', Value);
  if (P = 1) or (P = Len) then
    NotValidBinaryOfDoubleException;
  SetLength(IntPart, P - 1);
  for I := 1 to P - 1 do
    IntPart[I] := Value[I];
  for I := P + 1 to Len do
    if (Value[I] <> '0') and (Value[I] <> '1') then
      NotValidBinaryOfDoubleException;

  // calculate fractal part
  if P > 0 then
  begin
    Inc(P);
    Temp := 1 / 2;
    for I := P to Len do
    begin
      Result := Result + Temp * (Ord(Value[I]) - Ord('0'));
      Temp := Temp / 2;
    end;
  end;

  // build final result
  if Value[1] = '-' then
    Result := 0 - Result;
  Result := Result + BinaryToInt(IntPart);
end;

begin
  Writeln(DoubleToBin(582.24, 16));
  Writeln(DoubleToBin(582.24,0, 2));
  Writeln(DoubleToBin(-582.24, 0, 32));
  Writeln(DoubleToBin(-10/3,0,24));

  Writeln(FloatToStr(BinaryToDouble('-11.010101010101010101010101')));
  Writeln(FloatToStr(BinaryToDouble('0000001001000110.00111101')));
  Writeln(FloatToStr(BinaryToDouble('1001000110.00')));
  Writeln(FloatToStr(BinaryToDouble('-1001000110.00111101011100001010001111010111')));

  Readln;
end.

the result

0000001001000110.00111101
1001000110.00
-1001000110.00111101011100001010001111010111
-11.010101010101010101010101
-3.33333331346512
582.23828125
582
-582.239999999991

Hope you find it useful and for your quest after converting the fractal part then it is way simple that what you think, start with 1/2 and half it with each step, waling the bit from the left to the right.

 

ps : not fully tested but i think i mostly got it right at first try, if anyone find bug or have better and enhanced version of it or any other, please share here.

 

Share this post


Link to post

Ummm. I must be missing some deeper meaning here but what is the point of pretending that an integer values isn't already stored in binary format? I mean, I could understand if you were trying to implement bin/dec conversion on a denary computer but other than that this sounds like an algorithm for people that doesn't have access to computers.

  • Like 1

Share this post


Link to post
8 hours ago, dummzeuch said:

Hm, I always convert to hex as an intermediary step (and actually prefer hex constants in source code). and I can still do binary to hex and back in my head, back from the C64 times.

 

Thanks, that was also pointed out by others online and it will likely be in a follow-up article.  I simply didn't know about the double-dabble trick and thought it was kinda cool.  I don't do these number system conversions enough to be able to convert any lengthy amount in my head yet.  Lately I've been attempting to spend a lot more time learning rather than just always doing.  Unfortunately, I was always the work-harder and not the work-smarter type.  Few could out-work me, but many could out-smart me.  I want to combine the two, and maybe the next buyout will have an extra zero or two behind it.  Or, I'll simply enjoy it more.  Either way, it's a win.

 

Share this post


Link to post
5 hours ago, Kas Ob. said:

I have mountain of things that need to be done right now, but what to say !, i am bored to hell and looking something to do away from what is needed, so.

 

@Darian Miller this is special for you 

 

 

Literally LOL.  Thanks.  I'll try to absorb it!   🙂

 

Share this post


Link to post

@Darian Miller Just for fun

 

JUST FOUND NO BRACKET IN MY SOURCE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

what an HTML PAGE !!!!! plz fix

 x:= StrToInt(s); <<<<<<<<<<<<  cannot put bracket i

 

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, JvExStdCtrls, JvEdit,
  JvValidateEdit, Vcl.Mask, JvExMask, JvSpin;

type
  TForm1 = class(TForm)
    Button1: TButton;
    JvValidateEdit1: TJvValidateEdit;
    Label1: TLabel;
    Button2: TButton;
    JvValidateEdit2: TJvValidateEdit;
    Label2: TLabel;
    Button3: TButton;
    JvValidateEdit3: TJvValidateEdit;
    JvSpinEdit1: TJvSpinEdit;
    Label3: TLabel;
    Button4: TButton;
    Label4: TLabel;
    Label5: TLabel;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 Label1.Caption:='Answer';
 Label2.Caption:='Answer';
 Label3.Caption:='Answer';
end;

procedure TForm1.Button1Click(Sender: TObject); //to binary
var
i,x:integer;
ans:string;
begin
ans:='';
i:=  JvValidateEdit1.Value;
while i>0 do
begin
ans:=IntToStr(i mod 2) + ans ;
i :=i div 2;
//ans:=IntToStr(i mod 2)+ans ;
//i :=i div 2;
end;
Label1.Caption:=ans;
end;

procedure TForm1.Button2Click(Sender: TObject); //  to decimal
var
s:string;
i,ans:Integer;
begin
ans:=1;
  s:=JvValidateEdit2.Text;
  for I := 1 to length(s)-1 do
   ans:=(ans*2) +StrToInt(s[i+1]);
   Label2.Caption:=IntToStr(ans);
end;

procedure TForm1.Button3Click(Sender: TObject);  //fraction cal
var
f:real;
i,x:integer ;
ans:string;
begin
ans:='0.';
  f:=JvValidateEdit3.Value;
 for I := 1 to Round(JvSpinEdit1.Value) do
 begin
  f:=f*2;
  x:=Trunc(f);
  f:=Frac(f);
  ans:=ans+IntToStr(x);
  end;
  Label3.Caption:=ans;
end;

// https://indepth.dev/the-simple-math-behind-decimal-binary-conversion-algorithms/

procedure TForm1.Button4Click(Sender: TObject); //binary to fruction
var
s:string;
k:Real;
i,x:Integer;
ans:string;
begin
  k:=0;
 s:=Edit1.Text;
 for I :=Length(s) downto   1 do
 begin
 x:= StrToInt(s);
k:=(1/2)*(x+k);
 end;
 Label5.Caption:=FloatToStr(k);
end;

end.

 

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 283
  ClientWidth = 552
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -13
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 120
  TextHeight = 16
  object Label1: TLabel
    Left = 335
    Top = 35
    Width = 37
    Height = 19
    Caption = 'Label1'
  end
  object Label2: TLabel
    Left = 335
    Top = 73
    Width = 37
    Height = 16
    Caption = 'Label2'
  end
  object Label3: TLabel
    Left = 335
    Top = 119
    Width = 27
    Height = 16
    Caption = 'anse'
  end
  object Label4: TLabel
    Left = 187
    Top = 155
    Width = 16
    Height = 21
    Caption = '0.'
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -17
    Font.Name = 'Tahoma'
    Font.Style = [fsBold]
    ParentFont = False
  end
  object Label5: TLabel
    Left = 335
    Top = 159
    Width = 27
    Height = 16
    Caption = 'anse'
  end
  object Button1: TButton
    Left = 66
    Top = 32
    Width = 110
    Height = 25
    Caption = 'To Binary'
    TabOrder = 0
    OnClick = Button1Click
  end
  object JvValidateEdit1: TJvValidateEdit
    Left = 182
    Top = 32
    Width = 121
    Height = 24
    CriticalPoints.MaxValueIncluded = False
    CriticalPoints.MinValueIncluded = False
    EditText = '582'
    TabOrder = 1
  end
  object Button2: TButton
    Left = 68
    Top = 70
    Width = 108
    Height = 25
    Caption = 'To Decimal'
    TabOrder = 2
    OnClick = Button2Click
  end
  object JvValidateEdit2: TJvValidateEdit
    Left = 182
    Top = 70
    Width = 121
    Height = 24
    CriticalPoints.MaxValueIncluded = False
    CriticalPoints.MinValueIncluded = False
    EditText = '1001000110'
    TabOrder = 3
  end
  object Button3: TButton
    Left = 66
    Top = 116
    Width = 110
    Height = 25
    Caption = 'Fruction Calc'
    TabOrder = 4
    OnClick = Button3Click
  end
  object JvValidateEdit3: TJvValidateEdit
    Left = 182
    Top = 117
    Width = 121
    Height = 24
    CriticalPoints.MaxValueIncluded = False
    CriticalPoints.MinValueIncluded = False
    DisplayFormat = dfFloat
    DecimalPlaces = 10
    EditText = '0.24'
    TabOrder = 5
  end
  object JvSpinEdit1: TJvSpinEdit
    Left = 481
    Top = 116
    Width = 63
    Height = 24
    MaxValue = 10.000000000000000000
    MinValue = 1.000000000000000000
    Value = 8.000000000000000000
    TabOrder = 6
  end
  object Button4: TButton
    Left = 73
    Top = 155
    Width = 108
    Height = 25
    Caption = 'Binary Fruction'
    TabOrder = 7
    OnClick = Button4Click
  end
  object Edit1: TEdit
    Left = 208
    Top = 155
    Width = 95
    Height = 24
    NumbersOnly = True
    TabOrder = 8
    Text = '1011'
  end
end
 

Edited by limelect

Share this post


Link to post

@Lars Fosdal This is a test

</> [my test]

Nice now I understand

So if I put source I </> before the source right?

Edited by limelect

Share this post


Link to post
2 hours ago, limelect said:

@Lars Fosdal So if I put source I </> before the source right?

Take a look above the text editor, in the toolbar and look for the </> button, press that to insert code 🙂

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×