Metamorphing Machine I rather be this walking metamorphosis
than having that old formed opinion about everything!

Let's build a transpiler! Part 52 ½

This is a brief return to my transpiler series.
You can find the previous parts here.

WTF MAN?

For a moment, I signed up an Internet host. They advertise they are as cheap as $2.95/month and offer unlimited space.
Alas, it costs $2.95 only if you choose their 3 years plan, paying the whole amount in advance.
As I can't afford over one hundred bucks, I've chosen their 3 months plan. The exchange rate does not favor me right now.

By the way, this company will remain unnamed. Let's just say that that MAN in the title is formed by their initials and if you inspect this page carefully you will be able to learn who they are.

I intented to upload a quarter-million images and build a page where one could search and browse them.
With that in mind, I started uploading my images using FTP. It took forever.
Then I noticed they offer a page where you can select multiple files and upload them. This way was much faster.

The first problem I got was when I saw an upload error saying I've reached a 10,000 files limit. I've opened a ticket and they informed me that there is a 10,000 files cap indeed.
My bad. I did not read the TOS. OK, time to re-plan the whole thing. With some creative measures, I managed to stay below the file count limit.
Time to start uploading again.

The second problem I had was that it started to error out saying I've reached a 5GB limit.
I opened a second ticket and was informed that they do enforce this "soft" limit. Whaat? In what universe does "unlimited space" mean 5GB?
Pissed off I canceled it and was refunded for 2 months.

Their main offense is false advertising, of course, but there is a minor one I would like to bring to your attention, too.
How many mistakes can you find in the image below, depicting their upload page?

MAN upload page

Let me count them:
  1. You have a success message and an error message together. Does it mean we succeeded or not?
  2. The error message does not mention which files went wrong. You must figure them for yourself.
  3. The amount of bytes uploaded per second is negative. Does that mean that instead of uploading files, I have - gasp! - downloaded them?
  4. You can't see it in the image because it is not animated, but the percentage varies wildly. It goes up and down erratically.
    It could be replaced by a random number generator and be as informative as it.
  5. Is that time displayed there how long will it take to complete the upload, or how long has it been going? Your guess is as good as mine.
  6. Another thing you can't see in the picture is that when the green bar is about to touch the percentage, the percentage avoids it by "ducking".
    So we have that percentage number bouncing up and down on the screen, averting bar's "jabs". It's almost hilarious.
It is/was an awful experience. The first time I saw it I was confused as hell.
I guess that every single file being uploaded reports its progress at the same time, and they compete for screen time.
That's why the percentage changes at will without making any sense.
And that negative speed gives me the impression that some kind of global state is being messed up by the concurrent reports.

All in all, even though I was screwed and lost some money, I'm grateful I was refunded for two months. Due to not reading their TOS, I might or might not have been in disagreement with it, and they could have chosen not to give my money back.
It would be worse to be screwed twice...

Back to business

I counted my chickens before they were hatched. In my post of 2021-07-21, I said "One thing I am proud of is DecToStr. (...) A flawless decimal to string conversion."
Woe is me. It is flawed. It did not pass some more tests.
So I worked on it once more, and this time I am more confident it does its job as it should.
It is written in make-believe VB, but it was tested for real using VB6.
The basic logic behind it is: We have a number (Decimal) that is comprised of three Longs. So we split it into Longs. Every unit we have in the third higher Long, means we have to add 18,446 to a "higher" Double (variable H) and 744,073,709,551,616 to a middle Double (variable M).
Then apply the same logic to the two lower Longs. After that, convert the Doubles to a Currency and two Longs and start extracting the digits.

This is not me working back full time in the transpiler yet, but a small fix.

Next week we'll see four "different" uses of Javascript operators.

Andrej Biasic
2021-12-22

Private Type TwoLongs
Low As Long
High As Long
End Type

Function DecToStr(ByVal Value As Decimal) As String
Dim C As Integer 'Count
Dim D As Integer 'Digit
Dim G As Integer 'Goal
Dim I As Integer 'Index
Dim U As Integer 'Unit
Dim E As Long 'Exponent
Dim Y As Long 'Middle 9 digits
Dim Z As Long 'Low 6 digits
Dim X As Currency 'High digits (up to 14)
Dim H As Double 'High number
Dim M As Double 'Middle number
Dim L As Double 'Low number
Dim B As String * 31 'Result
Dim S As TwoLongs 'To split M (Double) into two Longs
Dim T As DecimalStruct

CopyMemory VarPtr(T), VarPtr(Value), SizeOf(Decimal)

' ( 1) 1 0000 0000 0000 0000 = 18 446 | 744 073 709 551 616
' ( 10) a 0000 0000 0000 0000 = 184 467 | 440 737 095 516 160
' ( 100) 64 0000 0000 0000 0000 = 1 844 674 | 407 370 955 161 600
' ( 1000) 3e8 0000 0000 0000 0000 = 18 446 744 | 073 709 551 616 000
' ( 10000) 2710 0000 0000 0000 0000 = 184 467 440 | 737 095 516 160 000
' ( 100000) 1 86a0 0000 0000 0000 0000 = 1 844 674 407 | 370 955 161 600 000
' ( 1000000) f 4240 0000 0000 0000 0000 = 18 446 744 073 | 709 551 616 000 000
' ( 10000000) 98 9680 0000 0000 0000 0000 = 184 467 440 737 | 095 516 160 000 000
' ( 100000000) 5f5 e100 0000 0000 0000 0000 = 1 844 674 407 370 | 955 161 600 000 000
' (1000000000) 3b9a ca00 0000 0000 0000 0000 = 18 446 744 073 709 | 551 616 000 000 000

While T.High < 0
T.High And= &H7FFFFFFF
H += 18446744073709#
M += 551616000000000#
T.High -= 1000000000

If T.High > 0 Then
T.High Or= &H80000000

ElseIf T.High < 0 Then
T.High Xor= &H80000000
End If
Wend

D = T.High \ 1000000000
H += 18446744073709# * D
M += 551616000000000# * D
T.High -= 1000000000# * D

D = T.High \ 100000000
H += 1844674407370# * D
M += 955161600000000# * D
T.High -= 100000000 * D

D = T.High \ 10000000
H += 184467440737# * D
M += 95516160000000# * D
T.High -= 10000000 * D

D = T.High \ 1000000
H += 18446744073# * D
M += 709551616000000# * D
T.High -= 1000000 * D

D = T.High \ 100000
H += 1844674407# * D
M += 370955161600000# * D
T.High -= 100000 * D

D = T.High \ 10000
H += 184467440# * D
M += 737095516160000# * D
T.High -= 10000& * D

D = T.High \ 1000
H += 18446744# * D
M += 73709551616000# * D
T.High -= 1000 * D

D = T.High \ 100
H += 1844674# * D
M += 407370955161600# * D
T.High -= 100 * D

D = T.High \ 10
H += 184467 * D
M += 440737095516160# * D
T.High -= 10 * D

H += 18446 * T.High + M / 1E+15

While M > 1E+15
M -= 1E+15
Wend

M += 744073709551616# * T.High

'---------- Move M# to S.High and S.Low ----------'
If M <> 0 Then
CopyMemory VarPtr(S), VarPtr(M), SizeOf(Double)
E = S.High
E And= &H7FF00000
E \= &H100000
E -= 1023

S.High And= &HFFFFF
S.High Or= &H100000
E = 52 - E

While E
E -= 1
S.Low >>>= 1
If S.High And 1 Then S.Low Or= &H80000000
S.High >>>= 1
Wend
End If
'-------------------------------------------------'

If Ovf(S.Low, T.Low) Then
If Ovf(S.High, 1) Then
H += 18446

If Ovf(S.Low, &H292500) Then
If Ovf(S.High, 1) Then
M += 18446
Else
S.High = UAdd(S.High, 1)
End If
End If

S.Low = UAdd(S.Low, &H292500)
If Ovf(S.High, &H2A4BB) Then M += 18446
S.High = UAdd(S.High, &H2A4BB)
End If

S.High = UAdd(S.High, 1)
End If

S.Low = UAdd(S.Low, T.Low)

If Ovf(S.High, T.Middle) Then
H += 18446

If Ovf(S.Low, &H292500) Then
If Ovf(S.High, 1) Then
M += 18446
Else
S.High = UAdd(S.High, 1)
End If
End If

S.Low = UAdd(S.Low, &H29250000)
If Ovf(S.High, &H2A4BB) Then M += 18446
S.High = UAdd(S.High, &H2A4BB)
End If

S.High = UAdd(S.High, T.Middle)

'-------------- Move S.High and S.Low to M and L ---------------'
' ( 1) 1 0000 0000 = 4 294 | 967 296
' ( 10) a 0000 0000 = 42 949 | 672 960
' ( 100) 64 0000 0000 = 429 496 | 729 600
' ( 1000) 3e8 0000 0000 = 4 294 967 | 296 000
' ( 10000) 2710 0000 0000 = 42 949 672 | 960 000
' ( 100000) 1 86a0 0000 0000 = 429 496 729 | 600 000
' ( 1000000) f 4240 0000 0000 = 4 294 967 296 | 000 000
' ( 10000000) 98 9680 0000 0000 = 42 949 672 960 | 000 000
' ( 100000000) 5f5 e100 0000 0000 = 429 496 729 600 | 000 000
' (1000000000) 3b9a ca00 0000 0000 = 4 294 967 296 000 | 000 000

While S.High < 0
S.High And= &H7FFFFFFF
M += 4294967296000#
S.High -= 1000000000

If S.High > 0 Then
S.High Or= &H80000000

ElseIf S.High < 0 Then
S.High Xor= &H80000000
End If
Wend

D = S.High \ 1000000000
M = 4294967296000# * D
S.High -= 1000000000# * D

D = S.High \ 100000000
M += 429496729600# * D
S.High -= 100000000 * D

D = S.High \ 10000000
M += 42949672960# * D
S.High -= 10000000 * D

D = S.High \ 1000000
M += 4294967296# * D
S.High -= 1000000 * D

D = S.High \ 100000
M += 429496729# * D
L += 600000 * D
S.High -= 100000 * D

D = S.High \ 10000
M += 42949672 * D
L += 960000 * D
S.High -= 10000& * D

D = S.High \ 1000
M += 4294967 * D
L += 296000 * D
S.High -= 1000 * D

D = S.High \ 100
M += 429496 * D
L += 729600 * D
S.High -= 100 * D

D = S.High \ 10
M += 42949 * D
L += 672960 * D
S.High -= 10 * D

M += 4294 * S.High
L += 967296 * S.High
L = UAdd(L, S.Low)
'---------------------------------------------------------------'

If L < 0 Then L += 4294967296#
If M < 0 Then M += 4294967296#
If H < 0 Then H += 4294967296#

X = (L / 1000000 - 0.49) \ 1
Z = L - X * 1000000#
M += X
X = (M / 1000000000 - 0.49) \ 1
Y = M - X * 1000000000#
X += H

G = 6
I = 31

Do While Z <> 0 And C <> G
U = Z Mod 10
Mid$(B, I, 1) = CStr(U)
I = I - 1
Z -= U
Z /= 10
C += 1

If C = T.Places Then
Mid$(B, I, 1) = DecSep
I = I - 1
End If
Loop

While (X <> 0 Or Y <> 0) And C <> G
Mid$(B, I, 1) = "0"
I = I - 1
C += 1

If C = T.Places Then
Mid$(B, I, 1) = DecSep
I = I - 1
End If
Wend

G = G + 9

Do While Y <> 0 And C <> G
U = Y Mod 10
Mid$(B, I, 1) = CStr(U)
I = I - 1
Y -= U
Y /= 10
C += 1

If C = T.Places Then
Mid$(B, I, 1) = DecSep
I = I - 1
End If
Loop

While X <> 0 And C <> G
Mid$(B, I, 1) = "0"
I = I - 1
C += 1

If C = T.Places Then
Mid$(B, I, 1) = DecSep
I = I - 1
End If
Wend

G += 7
Y = X / 10000000
Z = (X - Y * 10000000@ - 0.49) \ 1

While Z <> 0
U = Z Mod 10
Mid$(B, I, 1) = CStr(U)
I = I - 1
Z -= U
Z /= 10
C += 1

If C = T.Places Then
Mid$(B, I, 1) = DecSep
I = I - 1
End If
Wend

While Y <> 0 And C <> G
Mid$(B, I, 1) = "0"
I = I - 1
C += 1

If C = T.Places Then
Mid$(B, I, 1) = DecSep
I = I - 1
End If
Wend

While Y
U = Y Mod 10
Mid$(B, I, 1) = CStr(U)
I = I - 1
Y -= U
Y /= 10
C += 1

If C = T.Places Then
Mid$(B, I, 1) = DecSep
I = I - 1
End If
Wend

If T.Places = C Then
Mid$(B, I, 1) = "0"
I = I - 1
End If

If T.Sign Then
Mid$(B, I, 1) = "-"
I = I - 1
End If

Exit Mid$(B, I + 1)
End Function