Kotlin/Java formatting Double values - kotlin

My current formatting is this
DecimalFormat("#,##0.00").format(value)
I need to handle values like this
0.00 //ok
0.45 //ok
0.002 //Need to show 0.002 or 0.0020
0.0003 //Need to show 0.0003 or 0.00030
0.00004 //Need to show 0.00004 or 0.000040
0.00234567 //Need to show 0.0023
But sure the above code will not work on fractional part where a non zero value started at thousandth place else I will just ended up displaying 0.00 as if it is totally a zero value. I still want the above formatting with comma when dealing with whole number but also allowing me to format when non zero starts beyond hundredths place.
Further sample
0.0492 // 0.04 or 0.05 much better
700.356 // 700.35 or 700.36 much better
54232.542234 // 54,232.54

Try multiplying the number by 10 until you know you got to two non zero digits. This way you will get the number of decimal points you have to round up.
After that you use the NumberFormat to format the number like this:
val format = NumberFormat.getInstance()
format.maximumFractionDigits = nrOfDecimalPoints
val formattedNumber = format.format(yourNumber)
This way you will keep the thousands separator "," and the decimal will be cut off after two non zero digits.
EDIT
This is how the custom function looks like:
private fun customFormat(number: Double): String{
var temp = number - number.toInt()
temp *= 100
var nrDec = 2
if (number <= 0.0){
return "0.00"
}
if (temp >= 1.0){
val format = NumberFormat.getInstance(Locale.US)
format.maximumFractionDigits = nrDec
return format.format(number)
}
while (temp < 1.0 && nrDec < 15){
temp *= 10
nrDec ++
}
if((temp * 10 % 10) != 0.0){
nrDec++
}
val format = NumberFormat.getInstance(Locale.US)
format.maximumFractionDigits = nrDec
return format.format(number)
}

You can do it like this in order to cut of tailing 0:
public static void main(String []args){
double number1 = 0.2;
double number2 = 1.55;
double number3 = 0.00005;
double number4 = 0.50000;
DecimalFormat df = new DecimalFormat("###,##0.00#########");
System.out.println(df.format(number1)); // 0.20
System.out.println(df.format(number2)); // 1.55
System.out.println(df.format(number3)); // 0.00005
System.out.println(df.format(number4)); // 0.50
}
You just need to know how far your decimal digits should be checked.

Related

For loop must have an iterator()

I need this service in which if the person stays for longer than 30 minutes, they have to pay an extra $10 every 15 minutes (and for the fraction of the 15 as well).
I designed it like this so far:
var checkInTime: Calendar
val totalTime: Long
get() = (Calendar.getInstance().timeInMillis - checkInTime.timeInMillis) / MIN_IN_MILISEC
fun getTime(totalTime:Long): Int{
var finalPrice = 0
var initialPrice = 20
if(totalTime<31){
finalFee = initialPrice
} else {
val extraPrice = 10
val extraTime = 15
finalFee = initialPrice
for(extraTime in totalTime){
finalFee += extraTime
}
return finalFee
}
I get the error "For loop must have an iterator()" when I try to loop through the totalTime when it's more than 30 minutes so that I can add $10 every 15 extra minutes. I need some help as to how to add to the finalFee every extra 15 minutes the person stays since my method is not working.
Thank you.
Let's take a look at your getTime function:
You're using a Long as totalTime. You can measure it in minutes to simplify your calculation (since all time values are measured in minutes). Since a Long type in Kotlin stores a integer up to 9,223,372,036,854,775,807 and no soul on Earth will use your service for that long (this represents 17 billion milleniums), you can just use an Int.
You're not declaring the finalFee variable, thus the code will raise an
"Unresolved reference" error. Since you're not using the finalPrice variable, I'm assuming you wanted to use this instead.
You're trying to iterate over a numeric value (in this case, totalTime, which is a Long). You can iterate over each element of a List, but how would you iterate over each element of an integer? I'm assuming you want to do a certain action totalTime number of times. In this case, you would use ranges.
You're also not using the variables extraPrice and extraTime.
There's code that's common to both if-else conditions (finalPrice = initialPrice), so you can extract that to outside the if-statement.
Refactoring your function:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime >= 30) {
(0 until totalTime).forEach {
finalPrice += 15
}
}
return finalPrice
}
It's shorter, but still doesn't do what it's supposed to: let's suppose totalTime is equal to 45. The person got 30 minutes costing $20 and only have to pay $10 for every 15 minutes, therefore will only pay $30 total. Your function is considering that the person will have to pay $15 for every minute they stayed, because it uses a for-loop that goes from 0 to totalTime. For that, you need a for-loop that goes from 30 (the time limit) from the total time (the totalTime) every 15 minutes:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime > 30) {
(30 until totalTime step 15).forEach {
finalPrice += 10
}
}
return finalPrice
}
Better yet, you don't even need a for-loop, you can just use maths:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime > 30) {
finalPrice += ((totalTime - 30) / 15) * 10
// ^^^^^^^^^^^^^^^^ Get the exceeding time
// ^^^^^^^^^^^^^^^^^^^^^^^ How many 15 minutes are there?
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Put $10 for every 15 minutes
}
return finalPrice
}
The last part: your question said you need to consider the fraction of 15 as well. Therefore, you need to use a real value, not an integer. Let's change it to a Double:
fun getTime(totalTime: Int): Double {
var finalPrice = 20.0
if (totalTime > 30) {
finalPrice += ((totalTime - 30) / 15.0) * 10
}
return finalPrice
}
Let's test your function:
fun main() {
println(getTime(0)) // Outputs 20.0
println(getTime(10)) // Outputs 20.0
println(getTime(30)) // Outputs 20.0
println(getTime(45)) // Outputs 30.0
println(getTime(60)) // Outputs 40.0
println(getTime(70)) // Outputs 46.666...
}

Rounding error down when not adding a round number using RoundingMode HALF_UP in Kotlin

consider below method:
fun main() {
var costs = 0
var transactionFee = 1.325
var total = (costs + transactionFee).toRoundedUpDouble()
}
fun Double.toRoundedUpDouble(fraction: Int = 2) =
BigDecimal(this).setScale(fraction, RoundingMode.HALF_UP).toDouble()
I want a number with 2 decimal after the comma, rounded up from 5. e.g. 1.325 becomes 1.33. This works when I add a round number, but not when I don't:
Output:
5.00 + 1.325 becomes 6.33 = good
5 + 1.325 becomes 6.33 = good
1 + 1.325 becomes 2.33 = good
1.325 becomes 1.32 = NOT GOOD
0 + 1.325 becomes 1.32 = NOT GOOD
0.00 + 1.325 becomes 1.32 = NOT GOOD
0.000 + 1.325 becomes 1.32 = NOT GOOD
This thread doesn't answer my question.
You say that this thread doesn't answer your question, but I it really does.
As mentioned in that thread, double literals lie to you, and println as well.
To know the actual value that these literals give you, you can use BigDecimal this way:
println(BigDecimal(1.325)) // 1.3249999999999999555910790149937383830547332763671875
println(BigDecimal(0 + 1.325)) // 1.3249999999999999555910790149937383830547332763671875
println(BigDecimal(5 + 1.325)) // 6.32500000000000017763568394002504646778106689453125
If you want accurate results, use BigDecimal from the start, and make sure to initialize them with strings, not double literals:
fun main() {
var costs = BigDecimal.ZERO
var transactionFee = BigDecimal("1.325")
var total = (costs + transactionFee).roundedUp()
println(total) // 1.33
println(total.toDouble()) // 1.33
}
fun BigDecimal.roundedUp(fraction: Int = 2) = setScale(fraction, RoundingMode.HALF_UP)

Format a number to string, fill 0 when it's not enough two characters

I want to format the number to String and fill 0 when it's not enough two characters
fun formatDuration(val duration):String {
val minutes = duration.toInt() / 60
return "$minutes"
}
For example, if minutes is 6, it should displayed 06 rather than 6.
You can padStart the toString() result of minutes.
I tried your code in the Kotlin Playground and it wasn't compilable / runnable. For the following example, I had to change parts of your fun:
fun main() {
println(formatDuration(364.34))
}
fun formatDuration(duration: Double): String {
val minutes = duration.toInt() / 60
// fill the result to be of 2 characters, use 0 as padding char
return minutes.toString().padStart(2, '0')
}
Executing this results in the output 06.
Alternatively, you can simply use String.format() from Java, just
return "%02d".format(minutes)
instead of return minutes.toString().padStart(2, '0'), the result stays the same.
You can achive this with padStart
Example:
val padWithSpace = "125".padStart(5)
println("'$padWithSpace'") // ' 125'
val padWithChar = "a".padStart(5, '.')
println("'$padWithChar'") // '....a'
// string is returned as is, when its length is greater than the specified
val noPadding = "abcde".padStart(3)
println("'$noPadding'") // 'abcde'

How to calculate the swap (rollover) in mt5 in term of account currency

Backgound:
using mt5
"swap" (rollover) price is defined in points (0.00001/0.001) - 5-digit broker
account currency: USD
The question is: how to calculate the "swap value" in terms of acc. currency in mt5. With other words, how many cents i will paid for one day rollover?
Currently have this "mql5" script:
#include <Trade\SymbolInfo.mqh>
void OnStart() {
CSymbolInfo sym; // symbol informations object
sym.Name( ChartSymbol() ); // get the object for the current chart symbol
if( sym.SwapMode() == SYMBOL_SWAP_MODE_POINTS) {
double lot = 0.1;
double swapUSD_long = sym.SwapLong() * 0; // need help here
double swapUSD_short = sym.SwapShort() * 0; // need help here
PrintFormat(
"symbol: %s swap_long: %.2f swap_short: %.2f swapUSD_long: %.2f swapUSD_short: %.2f",
sym.Name(),
sym.SwapLong(),
sym.SwapShort(),
swapUSD_long,
swapUSD_short
);
}
}
When attaching the script to EURAUD, it prints to terminal:
symbol: EURAUD swap_long: -10.80 swap_short: 6.80 swapUSD_long: 0.00
swapUSD_short: 0.00
so: the rollover price is 6.8 points for the short position. How to convert it to USD with current rate? For this need:
find the pair with the acc currency (in this case need find AUDUSD)
get the rate of AUDUSD sym.Bid() or sym.Ask()
and ...
simply need some help ;)
If I understand right your question, you can use the TickValueProfit and TickValueLoss. If the swap to some direction is negative (you will pay) use the TickvalueLoss and when positive use TickValueProfit.
You can make a function for this like the next:
double swap_value_currency(double value_point, double tickprofit, double tickloss)
{
if( value_point == 0.0 ) { return(0.0); }
if( value_point < 0.0 ) {
return( val * tickloss );
}
return( value_point * tickprofit);
}
The swap_value_currency returns the swap value depending on winning or losing for one standard lot.
so your fragment of code can be:
if( sym.SwapMode() == SYMBOL_SWAP_MODE_POINTS)
{
double swval_long = swap_value_currency(sym.SwapLong(), sym.TickValueProfit(), sym.TickValueLoss());
double swval_short= swap_vallue_currency(sym.SwapShort(), sym.TickValueProfit(), sym.TickValueLoss() );
}
and because this is for one standard lot, you need multiply it with your lot size...

printf, sprintf print at least two decimal places

I'm trying to figure out how to use sprintf to print at least two decimal places and no leading zeros. For instance
input:
23
23.0
23.5
23.55
23.555
23.0000
output:
23.00
23.00
23.50
23.55
23.555
23.00
any formatting help would be appreciated
There is no such built-in format specifier. You could check if the number to be printed has two or fewer decimals (round to two decimals and compare), and if so use %.02f. If the number has more decimals, use a %g specifier. Here's an example in Ruby:
def print_two_dec(number)
rounded = (number*100).to_i / 100.0
if number == rounded
printf "%.02f\n", number
else
printf "%g\n", number
end
end
[ 23, 23.0, 23.5, 23.55, 23.555 ].each do |number|
print_two_dec(number)
end
Outputs:
23.00
23.00
23.50
23.55
23.555
in PHP you could use
<?php
$number = 0.56;
echo sprintf("%0.2f",$number);
In PHP, you may use the number_format function for this purpose, too, which also allows you to change delimiters.
In php this is what I did (inspired by this post). Maybe not the most elegant but... I made a function for printing numbers as strings. I wanted to be able to have flexibility so I have a couple of parameters.
PHP:
function print_num($num,$numdec,$atleast = false,$max_dec = -1)
{
$ret_norm = false;
if (!$atleast)
$ret_norm = true;
else //atleast = true
{
//Want at least $numdec decimals
//Do we have two or fewer and want to return two or fewer?
if ($num == ((int)($num*100)/100) & $numdec <= 2 )
$ret_norm = true;
else
{
//See if we have enough dec. already
$just_dec = substr((string)$num,strpos((string)$num,".") + 1);
if ($numdec >= strlen($just_dec))
$ret_norm = true;
else
{
//More decimals than at least value - make sure we don't go over max if set
if ( $max_dec >= 0 && strlen($just_dec) > $max_dec )
{
//Confine to max_dec length
$ret_norm = true;
$numdec = $max_dec; //Set for sprintf below
$num = number_format($num,$max_dec); //Round the value so doesn't just chop off
}
else if ($max_dec >= 0)
$ret_norm = false;
} //else
} //else
} //else atlest
if ($ret_norm)
return sprintf("%0.".$numdec."f",$num);
else
return sprintf("%s",$num); //print as is
} //print_num
And to call the function (to have at least two decimals but max 4:
print_num($mynum,2,true,4);
If the number is 34.1, you get 34.10
If the number is 34.12345 you get 34.1235
etc.
Does "23.555".toFixed(2) not do what I think it does? (Javascript)