in VB.net, if nth digit after decimal is Zero, then Round function will apply for 7 digit - vb.net

let say n decimal = 0.996010569
I have applied below code (round on 6th digit) :
txtDiscountRate.Text = Math.Round(Val(txtDiscountRate.Text.Trim), 6)
But since here its 6th digit is 0 (Zero), so its value become 0.99601.
But i wish it would be 0.996011.
logic is: if 6th digit is 0 or < 5 then it do Round from 7th digit
then our calculation will be right.
Please provide Code in VB.net.
Jerry
in above code.
CInt(Str(1).Char(5)) is showing error this error -----> " 'Char' is not a member of 'String'".
Scenario is described below:
in txtDiscountRate.text have value "0.996010500406591" .
in my coding i did
txtDiscountRate.Text = Math.Round(Val(txtDiscountRate.Text.Trim), 6) . (means considering round till digit throught)
so it giving value 0.99601 which is because of 6th digit after decimal is 0,
but i want to put condition, in decimal value, if on 6th digit after decimal is ( 0 or 1 or 2 or 3 or 4 ) and 7th digit after decimal is available then it round till 7th position.
else it round till 6th position.

Use the FormatNumber() function.

Maybe not the best and prettiest solution, but you can give it a try...
Dim Dec As Decimal = 0.996010569
Dim str() As String = Split(CStr(Dec), ".")
If CInt(Str(1).Chars(5)) < 5 Then 'It's Char number 5 since it's a zero-based index. So the first number = Index 0.
txtDiscountRate.Text = Math.Round(Val(txtDiscountRate.Text.Trim), 7)
Else
txtDiscountRate.Text = Math.Round(Val(txtDiscountRate.Text.Trim), 6)
End If

Related

Formatting a double variable using String Format to add up to 3 zero from the right

I got a price decimal which sometimes can be either 0.00002001 or 0.00002.
I want to display always 3 zeros from the right if the number is like 0.00002 so I'm looking it to be 0.00002000. If the number is 0.00002001 do not add anything.
I came accross some examples and other examplesin msdn and tried with
price.ToString.Format("{0:F4}", price)
but It doesn't actually change anything in the number.
And in the case number is like 123456789 I want it to display 123.456.789 which I've half solved using ToString("N2") but it's displaying also a .00 decimals which I don't want.
Some special cases here between the fractional and whole numbers, so they need to be handled differently.
Private Function formatWithTrailingZeros(number As Double) As String
If number Mod 1 > 0 Then ' has a fractional component
Return $"{number:0.00000000}"
Else
Dim formattedString = $"{number:N2}"
Return formattedString.Substring(0, formattedString.Length - 3)
End If
End Function
Dim price = 0.00002001
Console.WriteLine(formatWithTrailingZeros(price))
price = 0.00002
Console.WriteLine(formatWithTrailingZeros(price))
price = 123456789
Console.WriteLine(formatWithTrailingZeros(price))
price = 123456789.012345
Console.WriteLine(formatWithTrailingZeros(price))
0.00002001
0.00002000
123,456,789
123456789.01234500
If your second case with 123.456.789 is not based on your current culture, then you may need to replace , with . such as
Return formattedString.Substring(0, formattedString.Length - 3).Replace(",", ".")
Since you are using . both as a decimal separator and a thousands separator, I'm not sure how my example of 123456789.012345000 should look, but since you didn't ask, I'm not going to guess.

I want to know the specific reason why we have take those 256,.. numbers in the conversion below

Projected code is used to convert a date into integer and vice-versa. I want to know the reason why here we have used this specific hexadecimal codes and the number series to get back the date from int. If there is an article about this code sample it would also help me understand this code actually.
I have tried online Hex to Decimal conversion for this codes and found its a 256^1,256^2... even though trying not able to find the exact reason.
declare #dDate date = '2017-10-12'
declare #iDate int = 0
select #iDate = ( (datepart(year,#dDate)*65536 | datepart(month,#dDate)*256 | datepart(dd,#dDate)))
select (#iDate&0xfff0000)/65536 --year
select (#iDate&0xff00)/256 --Month
select (#iDate&0xff) --Date
& is an operator doing bitwise AND. "|" is bitwise OR. See here and here. Also see here for an explanation on using bitwise AND/OR to store multiple number values in a single number column.
This part:
#iDate&0xfff0000
will "mask", or eliminate/replace-with-zeros, the portion of iDate that isn't from 256^2. Then you divide by 65536 -- which is simply reversing the original math of multiplying the year by 65536.
If the concept of bitwise AND is foreign, I'll give an example that DOESN'T WORK in decimal. Bitwise AND converts the whole thing to binary and then masks things (like IP subnetting, if you're familiar with that).
Anyway, consider a decimal number 20171012. If such a thing as a decimal-wise AND existed, it could look like 20171012&11110000. The "1" places are "keepers" and the "0" places are "throw-aways". If you stack them vertically, the result is to keep the values with a "1" beneath them and replace the values with a "0" beneath them with a "0".
number 20171012
dec-wise AND 11110000
result 20170000
now the result isn't 2017, so you'd have to divide by 10000 to get 2017.
For 20171012&1100 you have to use implied leading zeros:
number 20171012
dec-wise AND 00001100
result 1000
I probably would have converted to int by adding the year*10000 and month * 100 and day. Reverting back I would use a combination of integer division and MOD. But I think the bitwise AND is perhaps a bit more elegant (particularly for getting the month).
Based on your comment, I will include how I have converted dates to int and reverted back:
declare #dDate date = '2017-10-12'
declare #iDate int
set #iDate = year(#dDate) * 10000 + month(#dDate) * 100 + day(#dDate)
select #iDate
select 'year', #iDate/10000 -- basic integer division provides the year
select 'month', (#iDate % 10000)/100 -- combine modulo and integer division to get the month
select 'day', #iDate % 100 -- basic modulo arithmetic provides the day
returns:
20171012
year 2017
month 10
day 12
This is bit manipulation.
Bit Shifting
Decimal 3 = Binary 11
If we do a left shift (<<) 4 bits in 3 it will become 48 which is equal to binary 110000 <- 4 zero bits added due to left shift
But since we don't have bit shifting operators in T-SQL therefore we can do the math.
Left Shifting of n bits in number x = x * 2^n
Therefore, multiple a number with 256 is actually left shift 8 bits from that number (2^8 = 256).
Later on when you do bitwise OR between 2 numbers they actually "concatenate" the bits up.
For example, you need to concatenate 2 binary numbers, (3) 11 and (2) 10, the resultant number should be 1110 = 14
So first we'll do 2 left shift in 3 = 3 * 2^2 = 12 and then we will do bitwise OR this number with the next number
12 = 1100
2 = 0010
OR
---------------
14 = 1110
Your example is actually saving the whole date in an integer variable which is actually efficient way of saving a date.

SQL | How to always round up regardless of the last integer value, even when that may be 0

I am currently outputting values out to 6 decimal places, and would like to round up the 6th place regardless of the integer value.
I have been using a CEILING() function so far which has worked great for values 1-9 on rounding up; however, in situations where I have the 7th decimal as 0 (ex: 2705.1520270), the function does not round up to 2705.152028.
select CEILING(price*1000000)/1000000 as PriceRound
from tc_alcf a (nolock)
Here is one approach:
SELECT ROUND(2705.1520270 + 0.0000005, 6);
2705.1520280
Demo
We can add 0.0000005 to the input and then just use SQL Server's ROUND function to 6 decimal places. This works because values with a sixth decimal place between 0 and 0.4999 (repeating) would become 5 to 0.9999 (repeating), meaning they would round up to the next digit. And values with already have 5 or greater in the sixth decimal place would not be bumped up to the next digit.
This problem should be familiar to many developers as the rounding half up problem.
Add 1 and use FLOOR():
select floor(price*1000000 + 1)/1000000 as PriceRound
from tc_alcf a
Or you can also shift the decimal by multiplying with the power function
CEILING(2705.1520275 * POWER(10,6)) / POWER(10,6)

SQL compare 3rd number aftee decimal point

I want to select myNum from myTable where myNum's 3rd number after decimal point is above 0.
So
123.456 would be returned.
123.450 would not.
(sybase)
SELECT myNum
FROM myTable
WHERE FLOOR(myNum*1000) % 10 > 0
Explanation:
Seeing is believing, so given the input 123.456:
myNum*1000 = 123456.xx (possibly data last 3rd decimal place)
FLOOR(myNum*1000) = 123456
FLOOR(myNum*1000) % 10 = 6, which is greater than zero

How to remove zeroes after the decimal point as an expression in SSRS

I have the following expression in one of my textbox in my SSRS Report:
=IIF(IsNothing(Lookup(Trim(Fields!venta_Cod_vendedor.Value) & "-" & ReportItems!Textbox233.Value, Fields!AgregarVentas.Value, Fields!venta_prom_sem.Value, "EfectividadDeFrecuencias_Ventas")) = True
,"0"
,IIF(Lookup(Trim(Fields!venta_Cod_vendedor.Value) & "-" & ReportItems!Textbox233.Value, Fields!Agregar.Value, Fields!total_cant_pos.Value, "EfectividadDeFrecuencias_Total") <> "0"
,FormatNumber(Lookup(Trim(Fields!venta_Cod_vendedor.Value) & "-" & ReportItems!Textbox233.Value, Fields!AgregarVentas.Value, Fields!venta_frecuencia.Value, "EfectividadDeFrecuencias_Ventas")
/ Lookup(Trim(Fields!venta_Cod_vendedor.Value) & "-" & ReportItems!Textbox233.Value, Fields!Agregar.Value, Fields!total_cant_pos.Value, "EfectividadDeFrecuencias_Total"),2)
,"0"))
That division will give me an int64 number, 15 digits (If such math operation gives that amount of decimal digits).
So the results are:
Now here is the tricky part:
My code behind that grabs the Dataset does a round and converts to decimal and then shows to a Crystal Report.
dr.venta_prom_sem = (Convert.ToDouble(dr.total_cant_pos) != 0 ? (Math.Round((Convert.ToDouble(dr.venta_frecuencia) / Convert.ToDouble(dr.total_cant_pos)), 2)).ToString() : "0");
So this will give me:
as you can see if I use a format Number the 1.3 will convert to 1,30 and that will be wrong, same as 1 (1,00). Now 1,339...etc will give me 1,34 and that is fine.
But check the 1.065, with FormatNumber that will give me 1.07 instead of 1.06.
So the thing is, how can I format my numbers to be the last non zero digit after the decimal point AND select the lower value if the (in this case) 3rd value is 5, instead of 1.07 be 1.06. I think If I use Ceiling or Floor it gives me the integer part.
Try this:
=ROUND(1.339,2,MidpointRounding.ToEven)
This gives: 1.34
And
=ROUND(1.065,2,MidpointRounding.ToEven)
Gives: 1.06
Let me know if this was helpful.