LibreOffice floating point precision - libreoffice

I am doing calculations on date and time using floating-point numbers. However, I notice that the calculated value is not as expected. Here is the code snippet.
Dim sTemp As Single, sLineDateTime As Single
Dim strTemp As String
strTemp = "2019-02-25"
sLineDateTime = DateValue(DateSerial(Left(strTemp, 4), Mid(strTemp, 6, 2), Right(strTemp, 2)))
strTemp = ""21:47:42"
REM TODO Time is being rounded off. Check
sTemp = TimeValue(TimeSerial(Left(strTemp, 2), Mid(strTemp, 4, 2), Right(strTemp, 2)))
sLineDateTime = sLineDateTime + sTemp
The output of the above computation is sLineDateTime="43521.906250" which when converted to date/time is "Mon 25-Feb-2019 09:45:00 PM". The actual value expected is "43521.908125" which translates to error of "0.001875000001746" or in other words 2 minutes 42 seconds. Any suggestions on how I can overcome this problem?

I did try before posting this and it did not help. I switched to using dates which is working perfectly for me now. Here is the code.
strTemp = "2019-02-25"
dLineDateTime = DateSerial(Left(strTemp, 4), Mid(strTemp, 6, 2), Right(strTemp, 2))
strTemp = "21:47:42"
dLineDateTime = dLineDateTime + TimeSerial(Left(strTemp, 2), Mid(strTemp, 4, 2), Right(strTemp, 2))

Related

prolog - Generating dates between dates

I need to generate all dates between two given dates.
My predicate date_between(DateLow, DateHigh, X) works correctly:
?- date_between(date(2020,2,15), date(2020,2,25), X).
X = date(2020, 2, 15) ;
X = date(2020, 2, 16) ;
....
X = date(2020, 2, 25) .
But I think predicate is too clumsy. Is there another approach to do the same but more elegant?
Should I translate back and forth Date to Seconds (Stamp) and Seconds to Date?
I have to compare dates through conversion in seconds?
You can see my code:
date_between(DateLow, DateHigh, DateLow) :-
datestd_stamp(DateLow, StampLow),
datestd_stamp(DateHigh, StampHigh),
StampLow =< StampHigh.
date_between(DateLow, DateHigh, X) :-
datestd_stamp(DateLow, StampLow),
datestd_stamp(DateHigh, StampHigh),
StampLow < StampHigh,
DateLow = date(Y,M,D),
Dnxt is D + 1,
date_time_stamp(date(Y,M,Dnxt,0,0,0,0,-,-), StampNext),
stamp_date_time(StampNext, Dat, 0),
date_time_value(date, Dat, DateNxt),
date_between(DateNxt, DateHigh, X).
datestd_stamp(Data, Stamp) :-
Data = date(Y,M,D),
date_time_stamp(date(Y,M,D,0,0,0,0,-,-), StampTmp),
round(StampTmp, Stamp).
I tried to improve the predicate. The execution time has definitely been reduced.
The predicate has become simpler and faster.
Old version:
?- time((bagof(X, (date_between(date(2020,1,1), date(2100,12,31), X)), Ls))).
% 680,466 inferences, 0.149 CPU in 0.149 seconds (100% CPU, 4563901 Lips)
Ls = [date(2020, 1, 1), date(2020, 1, 2), date(2020, 1, 3),
New version:
?- time((bagof(X, (date_between2(date(2020,1,1), date(2100,12,31), X)), Ls))).
% 207,106 inferences, 0.066 CPU in 0.066 seconds (100% CPU, 3157900 Lips)
Ls = [date(2020, 1, 1), date(2020, 1, 2), date(2020, 1, 3),
You can see new version of predicate:
date_between2(DateLow, DateHigh, DateLow) :-
DateLow #=< DateHigh.
date_between2(DateLow, DateHigh, X) :-
DateLow #< DateHigh,
DateLow = date(Y,M,D),
Dnxt is D + 1,
date_time_stamp(date(Y,M,Dnxt,0,0,0,0,-,-), StampNext),
stamp_date_time(StampNext, Dat, 0),
date_time_value(date, Dat, DateNxt),
date_between2(DateNxt, DateHigh, X).

Julia: PlotlyJS and relative bar subplots

I have recently started using PlotlyJS.
I am trying to create a subplots of relative bar charts (bar charts with barmode=relative). Unfortunately it seems that the bar charts lose their barmode attribute, when they become a subplot. For example:
# PlotlyJS
using PlotlyJS;
pltjs = PlotlyJS
function bar1()
trace1 = pltjs.bar(;x=[1, 2, 3, 4], y=[1, 4, 9, 16], name="Trace1")
trace2 = pltjs.bar(;x=[1, 2, 3, 4], y=[6, -8, -4.5, 8], name="Trace2")
data = [trace1, trace2];
layout = pltjs.Layout(;xaxis_title="X axis",
yaxis_title="Y axis",
barmode="relative",
title="Relative 1");
pltjs.plot(data, layout)
end
function bar2()
trace3 = pltjs.bar(;x=[1, 2, 3, 4], y=[-15, -3, 4.5, -8], name="Trace3")
trace4 = pltjs.bar(;x=[1, 2, 3, 4], y=[-1, 3, -3, -4], name="Trace4")
data = [trace3, trace4];
layout = pltjs.Layout(;xaxis_title="X axis",
yaxis_title="Y axis",
barmode="relative",
title="Relative 2");
pltjs.plot(data, layout)
end
p1 = bar1();
pltjs.savefig(p1, "./fig1.pdf") # This works
p2 = bar2();
pltjs.savefig(p2, "./fig2.pdf") # This works
p3 = [bar1() bar2()];
pltjs.savefig(p3, "./fig3.pdf") # This doesn't works
I have seen similar issues in other languages, but I wasn't able to find a workaround for Julia. Would you please explain me why doesn't work and how to fix it?
I managed to do it using the code below:
p3.plot.layout["barmode"] = "relative";

VBScript function to convert hex to unicode

I have hexadecimal string which consists of different languages letters.
Please help me with a vb-script function which converts this hexadecimal string to Unicode text.
For hex string "506F7274756775C3AA73" , I need to get "Português" as output.
I tried following function, it gives "Português" as output.
MsgBox ConvertHexToUnicode("506F7274756775C3AA73")
Function ConvertHexToUnicode(hexString)
Dim Strlen
Dim Charaset_array(20)
Dim i
Dim j
Strlen = Len(hexString)
i = 0
j = 1
Do
Charaset_array(i) = Mid(hexString,j, 2)
i = i + 1
j = j + 2
Loop While j < Strlen
ConvertHexToUnicode = ""
For Each chara In Charaset_array
If Not(IsEmpty(chara)) Then
ConvertHexToUnicode = ConvertHexToUnicode + ChrW("&H" & chara )
End If
Next
End Function
Use Mid() to cut your input string into hex numbers (strings), prepend &H to get hex literals, and ChrW() to build characters:
>> s = "00001F00"
>> WScript.Echo Mid(s, 5, 4)
>> WScript.Echo "&H" & Mid(s, 5, 4), CLng("&H" & Mid(s, 5, 4))
>> WScript.Echo ChrW("&H" & Mid(s, 5, 4)), AscW(ChrW("&H" & Mid(s, 5, 4)))
>>
1F00
&H1F00 7936
ἀ 7936

How to check if a number can be represented as a sum of some given numbers

I've got a list of some integers, e.g. [1, 2, 3, 4, 5, 10]
And I've another integer (N). For example, N = 19.
I want to check if my integer can be represented as a sum of any amount of numbers in my list:
19 = 10 + 5 + 4
or
19 = 10 + 4 + 3 + 2
Every number from the list can be used only once. N can raise up to 2 thousand or more. Size of the list can reach 200 integers.
Is there a good way to solve this problem?
4 years and a half later, this question is answered by Jonathan.
I want to post two implementations (bruteforce and Jonathan's) in Python and their performance comparison.
def check_sum_bruteforce(numbers, n):
# This bruteforce approach can be improved (for some cases) by
# returning True as soon as the needed sum is found;
sums = []
for number in numbers:
for sum_ in sums[:]:
sums.append(sum_ + number)
sums.append(number)
return n in sums
def check_sum_optimized(numbers, n):
sums1, sums2 = [], []
numbers1 = numbers[:len(numbers) // 2]
numbers2 = numbers[len(numbers) // 2:]
for sums, numbers_ in ((sums1, numbers1), (sums2, numbers2)):
for number in numbers_:
for sum_ in sums[:]:
sums.append(sum_ + number)
sums.append(number)
for sum_ in sums1:
if n - sum_ in sums2:
return True
return False
assert check_sum_bruteforce([1, 2, 3, 4, 5, 10], 19)
assert check_sum_optimized([1, 2, 3, 4, 5, 10], 19)
import timeit
print(
"Bruteforce approach (10000 times):",
timeit.timeit(
'check_sum_bruteforce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 200)',
number=10000,
globals=globals()
)
)
print(
"Optimized approach by Jonathan (10000 times):",
timeit.timeit(
'check_sum_optimized([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 200)',
number=10000,
globals=globals()
)
)
Output (the float numbers are seconds):
Bruteforce approach (10000 times): 1.830944365834205
Optimized approach by Jonathan (10000 times): 0.34162875449254027
The brute force approach requires generating 2^(array_size)-1 subsets to be summed and compared against target N.
The run time can be dramatically improved by simply splitting the problem in two. Store, in sets, all of the possible sums for one half of the array and the other half separately. It can now be determined by checking for every number n in one set if the complementN-n exists in the other set.
This optimization brings the complexity down to approximately: 2^(array_size/2)-1+2^(array_size/2)-1=2^(array_size/2 + 1)-2
Half of the original.
Here is a c++ implementation using this idea.
#include <bits/stdc++.h>
using namespace std;
bool sum_search(vector<int> myarray, int N) {
//values for splitting the array in two
int right=myarray.size()-1,middle=(myarray.size()-1)/2;
set<int> all_possible_sums1,all_possible_sums2;
//iterate over the first half of the array
for(int i=0;i<middle;i++) {
//buffer set that will hold new possible sums
set<int> buffer_set;
//every value currently in the set is used to make new possible sums
for(set<int>::iterator set_iterator=all_possible_sums1.begin();set_iterator!=all_possible_sums1.end();set_iterator++)
buffer_set.insert(myarray[i]+*set_iterator);
all_possible_sums1.insert(myarray[i]);
//transfer buffer into the main set
for(set<int>::iterator set_iterator=buffer_set.begin();set_iterator!=buffer_set.end();set_iterator++)
all_possible_sums1.insert(*set_iterator);
}
//iterator over the second half of the array
for(int i=middle;i<right+1;i++) {
set<int> buffer_set;
for(set<int>::iterator set_iterator=all_possible_sums2.begin();set_iterator!=all_possible_sums2.end();set_iterator++)
buffer_set.insert(myarray[i]+*set_iterator);
all_possible_sums2.insert(myarray[i]);
for(set<int>::iterator set_iterator=buffer_set.begin();set_iterator!=buffer_set.end();set_iterator++)
all_possible_sums2.insert(*set_iterator);
}
//for every element in the first set, check if the the second set has the complemenent to make N
for(set<int>::iterator set_iterator=all_possible_sums1.begin();set_iterator!=all_possible_sums1.end();set_iterator++)
if(all_possible_sums2.find(N-*set_iterator)!=all_possible_sums2.end())
return true;
return false;
}
Ugly and brute force approach:
a = [1, 2, 3, 4, 5, 10]
b = []
a.size.times do |c|
b << a.combination(c).select{|d| d.reduce(&:+) == 19 }
end
puts b.flatten(1).inspect

Excel, VB - Serialize an 8 digit date to mm/dd/yy

ISSUE
I am trying to convert a 8 digit number into a date while in an array. Examples of the entries are 12282009 or 12202007. There are other malformed entries in the field including dates entered as strings. I want the 8 digit number to be formatted as 12/28/09 or 12/20/07 respectively. I keep getting a type mismatch error on the third to last line below. How do I do this??
CODE
Dim del()
ReDim del(1 To importwsRowCount, 1 To 1)
del = Range("AH1:AH" & importwsRowCount).Value
Dim delChars As Long
Dim delType As String
For i = LBound(del, 1) To UBound(del, 1)
delChars = Len(del(i, 1)) 'Determine length of entry
If IsNumeric(del(i, 1)) = True Then 'Determine datatype of entry
delType = "Numeric"
del(i, 1) = Abs(del(i, 1))
Else
delType = "String"
del(i, 1) = UCase(del(i, 1))
End If
If delType = "Numeric" Then
If delChars = 8 Then
del(i, 1) = DateSerial((Right(del(i, 1), 4)), (Left(del(i, 1), 2)), (Mid(del(i, 1), 3, 2))) '<-- TYPE MISMATCH ERROR
End If
End If
ENTRY TEMPLATES
SEPT. 25, 20 (No year, no year! Delete.)
SEPT (No year, useless, delete.)
N/A (Rubbish! Deleted.)
LONG TIME AG (What moron thought this was a good idea, delete.)
JUNE 30, 200 (Apparently the field will only hold 12 characters, delete.)
CHARGED OFF (Useless, delete.)
94 DAYS (Take all characters preceding space and subtract from other field containing order date to obtain delinquent date.)
94 DPD (DPD in someones bright mind stands for Days Past Due I believe. Same as above.)
2008-7-15 12 (Not sure what additional number is, take all characters before space and transform.)
INVALID (Delete.)
BLANK (Do nothing.)
4/2/4/09 (Malformed date, delete.)
1/1/009 (Same as above.)
12282009 (Use nested LEFT and RIGHT and CONCATENATE with / in between.)
9202011 (Add leading zero, then same as above.)
92410 (Add leading zero, this will transform to 09/24/10)
41261 (Days since 31/12/1899, this will transform to 12/08/12)
1023 (Days since delinquent, subtract from ORDER DATE to get delinquent date.)
452 (Same as above.)
12 (Same as above.)
1432.84 (Monetary value, mistakenly entered by low IQ lackey. Delete.)
Right(Left(del(i, 1), 2), 6) is nonsensical.
The Left(del(i, 1), 2) part happens first and returns a 2-character string. If you then apply Right(..., 6) to that 2-character string you get an error.
The Mid function is needed here: Mid(del(i, 1), 3, 2)
Running the Abs function earlier changed the array entry from being a Variant with subtype String to being a Variant with subtype Double. This shouldn't necessarily affect the Left/Mid/Right functions but try:
del(i, 1) = CStr(del(i, 1))
del(i, 1) = DateSerial((Right(del(i, 1), 4)), (Left(del(i, 1), 2)), (Mid(del(i, 1), 3, 2)))
We need to identify what the actual value causing the error is so:
If delType = "Numeric" Then
If delChars = 8 Then
On Error Goto DateMismatchError
del(i, 1) = DateSerial((Right(del(i, 1), 4)), (Left(del(i, 1), 2)), (Mid(del(i, 1), 3, 2))) '<-- TYPE MISMATCH ERROR
On Error Goto 0
End If
End If
' at the end of your Sub or Function - I'm assuming Sub here
Exit Sub
DateMismatchError:
MsgBox "Date mismatch: error number " & Err.Number & ", " & Err.Description & _
" caused by data value: |" & del(i, 1) & "| at row " & i & ". Original data " & _
"value is |" & Range("AH" & i).Value2 & "|, displayed value is |" & _
Range("AH" & i).Text & "|, number format is |" & Range("AH" & i).NumberFormat & "|"
End Sub
You can use this shorter code to replace your array elements with formatted dates
It cuts down the amount of testing inside the loop to two IFs. If numeric test is run first - there is no point running a longer lenint test for strings that are not 8 characters
The string functions Left$, Mid$ etc are much quicker than their variant cousins Left, Mid etc
I have made a substituion for your importwsRowCount variable in the code below
Updated code to handle and dump results, now handles string tests and non-compliantnumbers as per barrowc comments
The code below puts the new dates into a second array, skipping the invalid dates
The second array is then dumped at `AI``
Sub ReCut2()
Dim del()
Dim X()
Dim lngCnt As Long
del = Range("AH1:Ah10").Value2
ReDim X(1 To UBound(del, 1), 1 To UBound(del, 2))
Dim delChars As Long
Dim delType As String
For lngCnt = LBound(del, 1) To UBound(del, 1)
If IsNumeric(del(lngCnt, 1)) Then
If Len(Int((del(lngCnt, 1)))) = 8 Then X(lngCnt, 1) = DateSerial(Right$(del(lngCnt, 1), 4), Left$(del(lngCnt, 1), 2), Mid$(del(lngCnt, 1), 3, 2))
End If
Next
[ai1].Resize(UBound(X, 1), UBound(X, 2)).Value2 = X
End Sub