Kotlin calculator can't remove double .0 in the end [duplicate] - kotlin

This question already has an answer here:
Drop un-needed decimal ".0"
(1 answer)
Closed 2 years ago.
fun equalsClick(view: View) {
val sec0perandText: String = resultTextView.text.toString()
var sec0perand: Double = 0.0.roundToInt()
if (!TextUtils.isEmpty(sec0perandText)) {
sec0perand = sec0perandText.toDouble()
}
when (operation) {
"+" -> resultTextView.text = (operand + sec0perand).toString()
"-" -> resultTextView.text = (operand - sec0perand).toString()
"*" -> resultTextView.text = (operand * sec0perand).toString()
"/" -> resultTextView.text = (operand / sec0perand).toString()
}
}
Getting output in double is not an option because it gives Integers .0 in the end. I tried adding .roundToInt() which didn't work, when compiled it gives following error: Type mismatch: inferred type is Int but Double was expected.

If I have understood correctly, you wanna get rid of the decimal zeros at the end of a double value (trailing zeros). If so, here is a clean solution.
Do all your calculations with double values and when you wanna print the result, do it this way:
resultTextView.text = String.format("%.0f", operand + sec0perand)
this will get rid of the decimal digits if they are zeros or other decimal values (it does not round your number just formats it)

I tried adding .roundToInt() which didn't work, when compiled it gives following error: Type mismatch: inferred type is Int but Double was expected.
You are just doing it in the wrong place, use
resultTextView.text = (operand + sec0perand).roundToInt().toString()
and so on.

Related

Wrong comparing of Double and Int numbers in Kotlin

I'm working on calculator project but when I tried to use two similar ways of comparing double and int numbers I got different results.
So my question is Why are these ways of comparing works differently?
//some code that parse the string
//...
//code of calculating:
fun calculateIn(queueNumbers: Queue<Double>, queueActions: Queue<Char>) {
var action: Char
var result = queueNumbers.poll()
var operand: Double
while (!queueNumbers.isEmpty()) {
operand = queueNumbers.poll()
action = queueActions.poll()
when (action) {
'-' -> result -= operand
'+' -> result += operand
'*' -> result *= operand
'/' -> result /= operand
'%' -> result = result % operand * -1.0
}
}
var pointNum = 8.3
println("pointNum = " + pointNum)
println(if(pointNum.compareTo(pointNum.toInt()) == 0) pointNum.toInt() else pointNum)
println("result = " + result)
println(if(result.compareTo(result.toInt()) == 0) result.toInt() else result)
}
Result of code:
"10.3 + -2" //input String
[10.3, -2.0] //queueNumbers
[+]//queueActions
pointNum = 8.3
8.3
result = 8.3
8
I think that is strange because if I run similar code I will get the correct result:
var pointNum = 8.3
println(if(pointNum.compareTo(pointNum.toInt()) == 0) pointNum.toInt() else pointNum)
So there is result of this code:
8.3
Full code on GitHub: https://github.com/Trilgon/LearningKotlin
I believe this is a bug in the compiler. Discussion is here, I copy my findings:
Minimal reproducible example:
fun test1(): Int {
val d: Double?
d = 8.3
return d.compareTo(8) // 0
}
fun test2(): Int {
val d: Double
d = 8.3
return d.compareTo(8) // 1
}
Technical difference between these two code samples is that the value is boxed in test1() and unboxed in test2(). If we look at the generated bytecode for test2(), everything looks as expected:
7: bipush 8
9: i2d
10: invokestatic #63 // Method java/lang/Double.compare:(DD)I
It converts integer value 8 to double and then compares both values as doubles.
But if we look into test1(), something bizarre happens there:
10: invokevirtual #52 // Method java/lang/Double.doubleValue:()D
13: d2i
14: bipush 8
16: invokestatic #58 // Method kotlin/jvm/internal/Intrinsics.compare:(II)I
It does the opposite: it converts double value 8.3 to integer and then compares values as integers. This is why it says values are the same.
What is interesting, even "Kotlin Bytecode" tool in IntelliJ shows the correct code for test1():
INVOKEVIRTUAL java/lang/Double.doubleValue ()D
BIPUSH 8
I2D
INVOKESTATIC java/lang/Double.compare (DD)I
But the real generated bytecode is different and gives different results.
I reported the problem: https://youtrack.jetbrains.com/issue/KT-52163
This was a weird and even funny problem to me, But I think I found out what's the problem.
In Kotlin Double class is defined inside Primitives.kt, well at least in the build-in files not in the actual source. Here Double class implements an interface named Comparable<Double> which is another built-in Kotlin file. You can see a portion of that interface:
public operator fun compareTo(other: T): Int
So let's return to your code. I suspend culprit of this problem is the very first line.
import java.util.*
Inside the java.util package there is another Comparable interface, I think since Queue is a Java class and the poll method may return a nullable value, and since you already imported everything inside java.util package then compareTo is called from Comparable from java.util not the one in Kotlin package.
The reason why Java's compareTo returns a different result is unknown to me.
I tried replacing java.util.* with:
import java.util.Queue
import java.util.LinkedList
But nothing changed.
However, I found another solution, just replace var result = queueNumbers.poll() with var result = queueNumbers.poll() ?: 0.0 or var result: Double = queueNumbers.poll() then it would be fixed!
//original
var result = queueNumbers.poll()
//method 1
var result : Double = queueNumbers.poll()
//method 2
var result = queueNumbers.poll() ?: 0.0

Input out of range for Int datatype, not passing a testcase

I am trying to solve the following question on LeetCode; Write a function that takes an unsigned integer and returns the number of '1' bits it has. Constraints: The input must be a binary string of length 32.
I have written the following code for that which works fine for inputs 00000000000000000000000000001011 and 00000000000000000000000010000000 (provided internally by the website) but give output 0 for input 11111111111111111111111111111101 and in my local compiler for the last input it says "out of range"
class Solution {
// you need treat n as an unsigned value
fun hammingWeight(n:Int):Int {
var num = n
var setCountBit = 0
while (num > 0) {
setCountBit++
num= num and num-1
}
return setCountBit
}
}
To correctly convert binary string to Int and avoid "out of range error", you need to do the following (I believe LeetCode does the same under the hood):
fun binaryStringToInt(s: String): Int = s.toUInt(radix = 2).toInt()
"11111111111111111111111111111101" is equivalent to 4294967293. This is greater than Int.MAX_VALUE, so it will be represented as negative number after .toInt() convertion (-3 in this case).
Actually, this problem could be solved with one-liner in Kotlin 1.4:
fun hammingWeight(n: Int): Int = n.countOneBits()
But LeetCode uses Kotlin 1.3.10, so you need to adjust your solution to handle negative Ints as well.
Please change the type of your input variable from Int to a type like Double .At the moment The given value is bigger than the maximum value that a type Int number can store.

How to convert digit to character in Kotlin?

I'm trying to find the simplest way to convert a digit (0..9) into the respective character '0'..'9' in Kotlin.
My initial attempt was to write the following code:
fun convertToCharacter() {
val number = 0
val character = number.toChar()
println(character)
}
Of course, after running, I quickly saw that this produces \u0000, and not '0' like I expected. Then, remembering from how to do this in Java, I modified the code to add '0', but then this would not compile.
fun convertToCharacter() {
val number = 0
val character = number.toChar() + '0'
println(character)
}
What is the appropriate way to convert a number into its respective character counterpart in Kotlin? Ideally, I'm trying to avoid pulling up the ASCII table to accomplish this (I know I can add 48 to the number since 48 -> '0' in ASCII).
val character = '0' + number
is the shortest way, given that the number is in range 0..9
Kotlin stdlib provides this function since 1.5.0.
fun Int.digitToChar(): Char
Returns the Char that represents this decimal digit. Throws an exception if this value is not in the range 0..9.
If this value is in 0..9, the decimal digit Char with code '0'.code + this is returned.
Example
println(5.digitToChar()) // 5
println(3.digitToChar(radix = 8)) // 3
println(10.digitToChar(radix = 16)) // A
println(20.digitToChar(radix = 36)) // K
Like you said, probably the easiest way to convert an Int to the Char representation of that same digit is to add 48 and call toChar():
val number = 3
val character = (number + 48).toChar()
println(character) // prints 3
If you don't want to have the magic 48 number in your program, you could first parse the number to a String and then use toCharArray()[0] to get the Char representation:
val number = 3
val character = number.toString().toCharArray()[0]
println(character) // prints 3
Edit: in the spirit of the attempt in your question, you can do math with '0'.toInt() and get the result you were expecting:
val number = 7
val character = (number + '0'.toInt()).toChar()
println(number) // prints 7
How about 0.toString() instead of 0.toChar() ? If you are specifically after single digits, then 0.toString()[0] will give you a Char type
You can use an extension like this:
fun Int.toReadableChar(): Char {
return ('0'.toInt() + this).toChar()
}
You can apply this to any other class you want :)
Example:
println(7.toReadableChar())
>> 7

Why single char and "single char String" not equal when converted to long (.toLong())

I wanted to sum the digits of Long variable and add it to the variable it self, I came with the next working code:
private fun Long.sumDigits(): Long {
var n = this
this.toString().forEach { n += it.toString().toLong() }
return n
}
Usage: assert(48.toLong() == 42.toLong().sumDigits())
I had to use it.toString() in order to get it work, so I came with the next test and I don't get it's results:
#Test
fun toLongEquality() {
println("'4' as Long = " + '4'.toLong())
println("\"4\" as Long = " + "4".toLong())
println("\"42\" as Long = " + "42".toLong())
assert('4'.toString().toLong() == 4.toLong())
}
Output:
'4' as Long = 52
"4" as Long = 4
"42" as Long = 42
Is it a good practice to use char.toString().toLong() or there is a better way to convert char to Long?
Does "4" represented by chars? Why it is not equal to it char representation?
From the documentation:
class Char : Comparable (source) Represents a 16-bit Unicode
character. On the JVM, non-nullable values of this type are
represented as values of the primitive type char.
fun toLong(): Long
Returns the value of this character as a Long.
When you use '4' as Long you actually get the Unicode (ASCII) code of the char '4'
As mTak says, Char represents a Unicode value. If you are using Kotlin on the JVM, you can define your function as follows:
private fun Long.sumDigits() = this.toString().map(Character::getNumericValue).sum().toLong()
There's no reason to return Long rather than Int, but I've kept it the same as in your question.
Non-JVM versions of Kotlin don't have the Character class; use map {it - '0'} instead.

How to get 1 decimal Float in swift [duplicate]

This question already has answers here:
Precision String Format Specifier In Swift
(31 answers)
Closed 8 years ago.
I want to extract 1 decimal float number from existing float number.
I have done this in Objective-C:
Make a float only show two decimal places
Any idea how to make it happen in Swift?
You can make the same in swift :
var formatter : NSString = NSString(format: "%.01f", myFloat)
Or like you want in one line :
println("Pro Forma:- \n Total Experience(In Years) = "+(NSString(format: "%.01f", myFloat)))
This work too with the old NSLog (but prefer println) :
NSLog("Pro Forma:- \n Total Experience(In Years) = %.01f \n", myFloat)
You can try this
var experience = 10.25
println("Pro Forma:- \n Total Experience(In Years) = " + NSString(format: "%.01f", experience))
How about an infix operator?
// Declare this at file level, anywhere in you project.
// Expressions of the form
// "format string" %% doubleValue
// will return a string. If the string is not a well formed format string, you'll
// just get the string back! If you use incorrect format specifiers (e.g. %d for double)
// you'll get 0 as the formatted value.
operator infix %% { }
#infix func %% (format: String, value: Double) -> String {
return NSString(format:format, value)
}
// ...
// You can then use it anywhere
let experience = 1.234
println("Pro Forma:- \n Total Experience(In Years) = %.01f" %% experience)
I've tried to do it with generics, but I can't see how. To make it work with multiple types, just overload it for those types - e.g.
operator infix %% { }
#infix func %% (format: String, value: Double) -> String {
return NSString(format:format, value)
}
#infix func %% (format: String, value: Float) -> String {
return NSString(format:format, value)
}
#infix func %% (format: String, value: Int) -> String {
return NSString(format:format, value)
}