Logic in Custom Rounding off - VB Script - QTP - vbscript

I have a data file where decimal points aren't specified for a decimal number. The number is just described in the layout for the data file as first 2 digits as real and next 2 digits as decimal and it varies for different fields, the real and decimal part
So an actual number 12345.6789 is specified as 123456789. When I want this to be rounded off to 2 decimal points to match the value in application, I use the below logic
Public Function Rounding(NumberValue, DecimalPoints, RoundOff)
Rounder= Roundoff+1
Difference = DecimalPoints - Rounder
NumberValue = Mid(NumberValue, 1, Len(NumberValue)-Difference)
RealNumber=Mid(NumberValue,1,Len(NumberValue)-Rounder)
DecimalNumber=Right(NumberValue,Rounder)
NumberValue = RealNumber&"."&DecimalNumber
NumberValue = Cdbl(NumberValue)
NumberValue = Round(NumberValue, Roundoff)
Rounding = FormatNumber(NumberValue,Difference+1,,,0)
End Function
However the problem with this logic is that I am not able to round off decimals when the number has 0 as the decimal value
For an Example, lets take 12345.0000 which I want to round off to 2 decimal points
My function returns it as 12345 whereas I want this to be returned as 12345.00
Any ideas on how this logic could be tweaked to get the desired output or is that not possible at all?

To get the decimal places, use the Formatnumber function. See http://msdn.microsoft.com/en-us/library/ws343esk(v=vs.84).aspx - the default is normally 2 decimal places, but it is region settings specific when using the defaults.
Your script also has a small issue if the decimalpoints variable matches the roundoff variable - it will not populate Rounding with a result. I am also not sure why you are comparing DecimalPoints to Roundoff (-1) ?
I've revised the entire routine - it should do what you want (although I don't know what values you are feeding it) - So now it will work like this:
Doing 4 digits:
Rounding (123450001, 4, 2)
Result:
12345.00
Doing 2 digits:
Rounding (123450001, 2, 2)
Result:
1234500.01
Doing 4 digits (increments if > .5)
Rounding (876512345678, 8, 4)
Result:
8765.1235
Revised simplified function that should do everything you are asking:
Public Function Rounding(NumberValue, DecimalPoints, RoundOff )
RealNumber = Mid(NumberValue, 1, Len(NumberValue)-DecimalPoints)
DecimalNumber = Round("." & Right(NumberValue,DecimalPoints), RoundOff)
Rounding = FormatNumber(RealNumber + DecimalNumber,RoundOff,,,0)
End Function
Here's a working version of your Function:
Public Function Rounding(NumberValue, DecimalPoints, RoundOff)
RealNumber=left(NumberValue,Len(NumberValue)-DecimalPoints)
DecimalNumber="." & Right(NumberValue,DecimalPoints)
NumberValue = RealNumber + DecimalNumber
NumberValue = Round(NumberValue,RoundOff)
Rounding = FormatNumber(NumberValue, RoundOff,,,0)
End Function

I'm pretty sure you won't be able to use the Round() function for what you need. Take a look at the FormatNumber() or FormatCurrency() functions as they have the option to "IncludeLeadingZero".
Take a look at the answer from the following link for more information:
vbscript round to 2 decimal places using Ccur

Related

float, round to 2 decimal places - Processing

I started learning processing since a short time ago and I came across a problem; When deviding 199.999 by 200 I want to outcome to be with 2 decimals (so the outcome should be 1 rounded of). Without formatting the outcome is 0.999995.
Code for formatting to String with 2 decimal:
float money = 199.999;
int munten = 200;
String calc1 = nf(money/munten,0,2);
println(calc1);
float calc2 = float(calc1);
println(calc2);
Prints:
1,0
NaN
I think float() wont work cause there is a comma in the String instead of a dot, I'm not sure tough. But how can I round a number to 2 decimal and still let it be a float?
Thanks for taking your time to read this,
When I run your example on Processing 3.3.6 / macOS 10.12 (US), I get "1.00" and "1.0". This could be due to your number formatting settings creating output strings that are then not read correctly by nf().
float money;
int munten;
String s;
float f;
money = 199.999;
munten = 200;
s = nf(money/munten, 0, 2);
println(s); // "1.00" -- or "1,0" etc. in different os language locales
f = float(s);
println(f); // "1.0" -- or NaN error if above is not 1.0 format
f = money/munten;
println(f); // 0.999995
s = nf(f, 0, 2);
println(s); // 1.00 -- or local format
You can see what should be happening more clearly in the second bit of code -- don't try to convert into a String and then back out again; don't store numbers in Strings. Instead, keep everything in numeric variables up until the moment you need to display.
Also keep in mind that nf() isn't really for rounding precision, although it is often used that way:
nf() is used to add zeros to the left and/or right of a number. This is typically for aligning a list of numbers. To remove digits from a floating-point number, use the int(), ceil(), floor(), or round() functions. https://processing.org/reference/nf_.html
If you need to work around your locale, you can use Java String formatting in Processing to do so:
float fval = 199.999/200;
println(fval); // 0.999995
String s = String.format(java.util.Locale.US,"%.2f", fval);
println(s); // 1.00
See https://stackoverflow.com/a/5383201/7207622 for more discussion of the Java approach.

Generating Random Numbers and Letters

Keep getting this error sometimes when mid is ZERO:
Invalid procedure call or argument: 'Mid'
How would I fix this?
Function CreateRandomString(iSize)
Const VALID_TEXT = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
Dim sNewSearchTag
Dim I
For I = 0 To iSize
Randomize
sNewSearchTag = sNewSearchTag & Mid(VALID_TEXT,Round(Rnd * Len(VALID_TEXT)),1)
Next
CreateRandomString = sNewSearchTag
End Function
For the random range to be correct you need to make sure the random value generated is between 1 and the length of the VALID_TEXT string value.
The simple formula to do this using Rnd() is
(Rnd() * Len(VALID_TEXT)) + 1
also move Randomize() outside the loop, as it is you'll just make it less random as you're resetting the seed with every iteration of the loop.
The reason for the error is Mid() expects a valid start and size, which a zero value is not. See this question for more information.
More information about random number ranges can be found in this answer to another question.
The second argument of Mid is 1 based. That means that if you did:
Mid(VALID_TEXT,1,1)
you will get "a", not "b" as you might be expecting.
An easy fix would be to add 1 to the second argument, but then you'll run into the same problem on the top end. Typically people will round a random number down after multiplying it instead of using Math.Round, either view Math.Floor or Integer truncation.

ElasticSearch Script Field return incorrect value

I have a document with cd field is 44.4
When i using "script_fields as below :
"doc['cd'].value + 1"
script_fields value will return 45.400001525878906
Please help me to use script_fields value return to 45.4
For rounding up your floating point values use Math.round() function.
The below will return the value after two decimal places.
Math.round(doc['your_custom_type_var'].value * 100.0)/100.0
If you want to round up after 3 decimal places then change the value as like:
Math.round(doc['your_custom_type_var'].value * 1000.0)/1000.0
For your case do the followings :
Math.round((doc['cd'].value + 1) * 10.0 - 0.5 )/10.0 // -0.5 for getting the correct result. For this 45.401 and 45.601 both will return 45.6
Notes
Math.round() function returns the closest int to the argument. For example
Math.round(45.40000152) // will return the value 45
Math.round(45.60000152) // will return the value 46
To get the correct answer you can substitute 0.5 to the actual number and then rounding up.Then it will return the value which we want to get.
First we multiple the value with 10.0 for moving the decimal place one unit right(for the above value 454.0000152). After rounding this cuts of the floating point values(for the above value 454), and so we divide the whole numbers by 10.0 for getting the value which rounded up by one decimal place from the actual value(for the above value 45.4).
Think, it will help.

Hashing a long integer ID into a smaller string

Here is the problem, where I need to transform an ID (defined as a long integer) to a smaller alfanumeric identifier. The details are the following:
Each individual on the problem as an unique ID, a long integer of size 13 (something like 123123412341234).
I need to generate a smaller representation of this unique ID, a alfanumeric string, something like A1CB3X. The problem is that 5 or 6 character length will not be enough to represent such a large integer.
The new ID (eg A1CB3X) should be valid in a context where we know that only a small number of individuals are present (less than 500). The new ID should be unique within that small set of individuals.
The new ID (eg A1CB3X) should be the result of a calculation made over the original ID. This means that taking the original ID elsewhere and applying the same calculation, we should get the same new ID (eg A1CB3X).
This calculation should occur when the individual is added to the set, meaning that not all individuals belonging to that set will be know at that time.
Any directions on how to solve such a problem?
Assuming that you don't need a formula that goes in both directions (which is impossible if you are reducing a 13-digit number to a 5 or 6-character alphanum string):
If you can have up to 6 alphanumeric characters that gives you 366 = 2,176,782,336 possibilities, assuming only numbers and uppercase letters.
To map your larger 13-digit number onto this space, you can take a modulo of some prime number slightly smaller than that, for example 2,176,782,317, the encode it with base-36 encoding.
alphanum_id = base36encode(longnumber_id % 2176782317)
For a set of 500, this gives you a
2176782317P500 / 2176782317500 chance of a collision
(P is permutation)
Best option is to change the base to 62 using case sensitive characters
If you want it to be shorter, you can add unicode characters. See below.
Here is javascript code for you: https://jsfiddle.net/vewmdt85/1/
function compress(n) {
var symbols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïð'.split('');
var d = n;
var compressed = '';
while (d >= 1) {
compressed = symbols[(d - (symbols.length * Math.floor(d / symbols.length)))] + compressed;
d = Math.floor(d / symbols.length);
}
return compressed;
}
$('input').keyup(function() {
$('span').html(compress($(this).val()))
})
$('span').html(compress($('input').val()))
How about using some base-X conversion, for example 123123412341234 becomes 17N644R7CI in base-36 and 9999999999999 becomes 3JLXPT2PR?
If you need a mapping that works both directions, you can simply go for a larger base.
Meaning: using base 16, you can reduce 1 to 16 to a single character.
So, base36 is the "maximum" that allows for shorter strings (when 1-1 mapping is required)!

Automatic type conversion in Visual Basic 6.0

When we convert a float to integer in visual basic 6.0, how does it round off the fractional part? I am talkin about the automatic type conversion.
If we assign like
Dim i as Integer
i=5.5
msgbox i
What will it print? 5 or 6 ??
I was getting "5" a couple of months before. One day it started giving me 6!
Any idea whats goin wrong? Did microsoft released some patches to fix something?
Update : 5.5 gets converted to 6 but 8.5 to 8 !
Update 2 : Adding CInt makes no difference. CInt(5.5) gives 6 and Cint(8.5) gives 8!! Kinda weired behaviour. I should try something like floor(x + 0.49);
Part of this is in the VB6 help: topic Type Conversion Functions. Unfortunately it's one of the topics that's not in the VB6 documentation on the MSDN website, but if you've installed the help with VB6, it will be there.
When the fractional part is exactly 0.5, CInt and CLng always round it to the nearest even number. For example, 0.5 rounds to 0, and 1.5 rounds to 2. CInt and CLng differ from the Fix and Int functions, which truncate, rather than round, the fractional part of a number. Also, Fix and Int always return a value of the same type as is passed in.
Implicit type coercion - a.k.a. "evil type coercion (PDF)" - from a floating point number to a whole number uses the same rounding rules as CInt and CLng. This behaviour doesn't seem to be documented anywhere in the manual.
If you want to round up when the fractional part is >= 0.5, and down otherwise, a simple way to do it is
n = Int(x + 0.5)
And off the top of my head, here's my briefer version of Mike Spross's function which is a replacement for the VB6 Round function.
'Function corrected, now it works.
Public Function RoundNumber(ByVal value As Currency, Optional PlacesAfterDecimal As Integer = 0) As Currency
Dim nMultiplier As Long
nMultiplier = 10 ^ PlacesAfterDecimal
RoundNumber = Fix(0.5 * Sgn(value) + value * nMultiplier) / CDbl(nMultiplier)
End Function
Sample output:
Debug.Print RoundNumber(1.6) '2'
Debug.Print RoundNumber(-4.8) '-5'
Debug.Print RoundNumber(101.7) '102'
Debug.Print RoundNumber(12.535, 2) '12.54'
Update: After some googling, I came across the following article:
It is not a "bug", it is the way VB was
designed to work. It uses something
known as Banker's rounding which, if
the number ends in exactly 5 and you
want to round to the position in front
of the 5, it rounds numbers down if
the number in front of the 5's
position is even and rounds up
otherwise. It is supposed to protect
against repeated calculation using
rounded numbers so that answer aren't
always biased upward. For more on this
issue than you probably want to know,
see this link
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q196652
This explains the (apparent) weird behavior:
Cint(5.5) 'Should be 6'
Cint(8.5) 'Should be 8'
Old Update:
Perhaps you should be more explicit: use CInt, instead of simply assigning a float to an integer. E.g:
Dim i as Integer
i = CInt(5.5)
MsgBox i
The changed behaviour sounds worrying indeed, however the correct answer surley is 6. Scroll down to "Round to even method" on Wikipedia, Rounding for an explanation.
As others have already pointed out, the "weird behavior" you're seeing is due to the fact that VB6 uses Banker's Rounding when rounding fractional values.
Update 2 : Adding CInt makes no
difference. CInt(5.5) gives 6 and
Cint(8.5) gives 8!!
That is also normal. CInt always rounds (again using the Banker's Rounding method) before performing a conversion.
If you have a number with a fractional part and simply want to truncate it (ignore the portion after the decimal point), you can use either the Fix or the Int function:
Fix(1.5) = 1
Fix(300.4) = 300
Fix(-12.394) = -12
Int works the same way as Fix, except for the fact that it rounds negative numbers down to the next-lowest negative number:
Int(1.5) = 1
Int(300.4) = 300
Int(-12.394) = -13
If you actually want to round a number according to the rules most people are familiar with, you will have to write your own function to do it. Below is an example rounding that will round up when the fractional part is greater than or equal to .5, and round down otherwise:
EDIT: See MarkJ's answer for a much simpler (and probably faster) version of this function.
' Rounds value to the specified number of places'
' Probably could be optimized. I just wrote it off the top of my head,'
' but it seems to work.'
Public Function RoundNumber(ByVal value As Double, Optional PlacesAfterDecimal As Integer = 0) As Double
Dim expandedValue As Double
Dim returnValue As Double
Dim bRoundUp As Boolean
expandedValue = value
expandedValue = expandedValue * 10 ^ (PlacesAfterDecimal + 1)
expandedValue = Fix(expandedValue)
bRoundUp = (Abs(expandedValue) Mod 10) >= 5
If bRoundUp Then
expandedValue = (Fix(expandedValue / 10) + Sgn(value)) * 10
Else
expandedValue = Fix(expandedValue / 10) * 10
End If
returnValue = expandedValue / 10 ^ (PlacesAfterDecimal + 1)
RoundNumber = returnValue
End Function
Examples
Debug.Print RoundNumber(1.6) '2'
Debug.Print RoundNumber(-4.8) '-5'
Debug.Print RoundNumber(101.7) '102'
Debug.Print RoundNumber(12.535, 2) '12.54'
The VB6 Round() function uses a Banker's Rounding method. MS KB Article 225330 (http://support.microsoft.com/kb/225330) talks about this indirectly by comparing VBA in Office 2000 to Excel's native behavior and describes it this way:
When a number with an even integer ends in .5, Visual Basic rounds the number (down) to the nearest even whole number. [...] This difference [between VBA and Excel] is only for numbers ending in a .5 and is the same with other fractional numbers.
If you need different behavior, I'm afraid you'll have to have to specify it yourself.

Resources