Make advanced number calculations? 2.1k equal to 2100 etc..? - java

So as the title says, if the input for example was 2.1k it should equal to 2100, if it was 3.7k it would be 3700 and so on. I have some code as following, I haven't really tried anything, just thinking about how the formula could be:
String arg = args[0];
if(arg.contains("k")) {
args[0].replace("k", "000");
}

You could check if the arg ends with "k", if it does parse the double value preceeding every character before "K" and multiply by 1000. Something like
String arg = "2.1k";
if (arg.endsWith("k")) {
int val = (int) (Double.parseDouble(arg.substring(0, arg.length() - 1))
* 1000);
arg = String.valueOf(val);
}
System.out.println(arg);
Outputs
2100

For the k example it would be:
int count = StringUtils.countMatches(arg, "k");//count the amount of k's
double decNumber = Double.parseDouble(arg.replace("k", "");//removes all k's and parse to a double
double finalNumber = decNumber * Math.pow(1000, k);//multiple by 1000^k
This works for any amount of k's AFTER the decimal number.

The correct way to do this looks more like:
String arg = args[0];
if(arg.contains("k")) {
newVal = args[0].replace("k", ""); //just drop the K and be left with a decimal
newVal = parseInt(args[0] * 1000); //New value is whatever was passed in times 1000
}

Related

How to move the digit in a double to the end without converting to string in Java

I am trying to make my number move the first character to the end.
For example I would have my double d.
double d = 12345.6;
double result = 2345.61;
Currently I am removing the first character of d with:
d = d % (int) Math.pow(10, (int) Math.log10(d));
But I do not know how to store the character I am removing so I could put it at the end. I know I could just convert d into an array or a string, but I want to keep it as a double if at all possible.
I am getting my double from a nanosecond clock using Instant.now, so I can guarantee it starts as an 8 digit positive int, which I start by adding .0 to so I can make it a double. I know I can just use string (as I mentioned in the post), but I was wondering if there was a way to do it without conversions.
Thanks for helping!
(this is my first post I apologize if it is bad)
This is a pretty tough problem, and this isn't a working answer but it is pretty close. The only trouble I ran into was java adding decimals to the end of my doubles because it can't represent a number very well. My solution might get you on the right path. The appendChar was messing up because it was adding digits to the end of the double, other than that problem this would have worked.
public static void main(String[] args) {
double test = 4234.1211;
boolean hasDecimals = test % 1 > 0;
double[] leadChar = getLeadDigitAndMulti(test);
double appendedValue = appendLeadChar(test, (int) leadChar[1], hasDecimals);
}
public static double[] getLeadDigitAndMulti(double value) {
double[] result = new double[2];
int multiplier = 10;
int currentMultiplier = 1;
while (value > currentMultiplier) {
currentMultiplier *= multiplier;
}
currentMultiplier /= multiplier;
double trail = value % (currentMultiplier);
result[0] = currentMultiplier;
double lead = value - trail;
lead /= currentMultiplier;
result[1] = lead;
return result;
}
public static double appendLeadChar(double value, int leadChar, boolean hasDecimals) {
if (!hasDecimals) {
return (value * 10) + leadChar;
}
int multiplier = 10;
double currentMultiplier = 1;
while (value > 0) {
value %= currentMultiplier;
currentMultiplier = currentMultiplier / multiplier;
}
return 0;
}
I would start with at least figuring out how many digits long your double is. I'm not too sure of how to make it work but I saw another question that would answer it. Here is the link to that thread:
Number of decimal digits in a double
And the closest code on there that I could find to find the length would be:
double d= 234.12413;
String text = Double.toString(Math.abs(d));
int integerPlaces = text.indexOf('.');
int decimalPlaces = text.length() - integerPlaces - 1;
NOTE THIS SEGMENT OF CODE IS NOT MINE, credit goes to Peter Lawrey who originally answered this in the linked thread.
Then using code or modified code similar to above ^ assuming you would find how to find the length of the double or the total number of digits of your double, you would create a new int or double variable that would store the double and round it using BigDecimal to the highest place value. The place that the BigDecimal will round to will be set using a 10*pow(x) where x is the number of places AFTER the decimal.
Sorry I am unable to provide code on how to make this actually run because I am pretty new to java. Here is what I mean in more detailed pseudocode:
double d = 12345.6; //the double you are evaluating
double dNoDecimal; //will be rounded to have no decimal places in order to calculate place of the 1st digit
double dRoundedFirstDigit; //stores the rounded number with only the 1st digit
double firstDigit; //stores first digit
dNoDecimal = d; //transfers value
dNoDecimal = [use BigDecimal to round so no decimal places will be left]
//dNoDecimal would be equal to 12345 right now
[use above code to find total amount of place values]
[knowing place values use BigDecimal to round and isolate 1st digit of double]
dRoundedFirstDigit = dNoDecimal; //transfers value
dRoundedFirstDigit = [round using BigDecimal to leave only 1st digit]
firstDigit = [dRoundedFirstDigit cut down to 1st digit value using length found from before, again an equation will be needed]
//Now use reverse process
//do the same thing as above, but find the number of decimals by rounding down to leave only decimals (leaving only .6)
//find the length
//use length to calculate what to add to the original value to move the digit to the end (in this case would be d += firstDigit*Math.pow(10,-2))
I apologize if I just made everything seem more confusing, but I tried my best, hope this helps.
Also, doing this without an array or string is really difficult... may I ask why you need to do it without one?

Get a numer decimal part as Integer using only math

Edit: This has to do with how computers handle floating point operations, a fact that every programmer faces once in a lifetime. I didn't understand this correctly when I asked the question.
I know the simplest way to start dealing with this would be:
val floatNumber: Float = 123.456f
val decimalPart = floatNumber - floatNumber.toInt() //This would be 0.456 (I don't care about precision as this is not the main objective of my question)
Now in a real world with a pen and a piece of paper, if I want to "convert" the decimal part 0.456 to integer, I just need to multiply 0.456 * 1000, and I get the desired result, which is 456 (an integer number).
Many proposed solutions suggest splitting the number as string and extracting the decimal part this way, but I need the solution to be obtained mathematically, not using strings.
Given a number, with an unknown number of decimals (convert to string and counting chars after . or , is not acceptable), I need to "extract" it's decimal part as an integer using only math.
Read questions like this with no luck:
How to get the decimal part of a float?
How to extract fractional digits of double/BigDecimal
If someone knows a kotlin language solution, it would be great. I will post this question also on the math platform just in case.
How do I get whole and fractional parts from double in JSP/Java?
Update:
Is there a "mathematical" way to "calculate" how many decimals a number has? (It is obvious when you convert to string and count the chars, but I need to avoid using strings) It would be great cause calculating: decimal (0.456) * 10 * number of decimals(3) will produce the desired result.
Update 2
This is not my use-case, but I guess it will clarify the idea:
Suppose you want to calculate a constant(such as PI), and want to return an integer with at most 50 digits of the decimal part of the constant. The constant doesn't have to be necessarily infinite (can be for example 0.5, in which case "5" will be returned)
I would just multiply the fractional number by 10 (or move the decimal point to the right) until it has no fractional part left:
public static long fractionalDigitsLong(BigDecimal value) {
BigDecimal fractional = value.remainder(BigDecimal.ONE);
long digits;
do {
fractional = fractional.movePointRight(1); // or multiply(BigDecimal.TEN)
digits = fractional.longValue();
} while (fractional.compareTo(BigDecimal.valueOf(digits)) != 0);
return digits;
}
Note 1: using BigDecimal to avoid floating point precision problems
Note 2: using compareTo since equals also compares the scale ("0.0" not equals "0.00")
(sure the BigDecimal already knows the size of the fractional part, just the value returned by scale())
Complement:
If using BigDecimal the whole problem can be compressed to:
public static BigInteger fractionalDigits(BigDecimal value) {
return value.remainder(BigDecimal.ONE).stripTrailingZeros().unscaledValue();
}
stripping zeros can be suppressed if desired
I am not sure if it counts against you on this specific problem if you use some String converters with a method(). That is one way to get the proper answer. I know that you stated you couldn't use String, but would you be able to use Strings within a Custom made method? That could get you the answer that you need with precision. Here is the class that could help us convert the number:
class NumConvert{
String theNum;
public NumConvert(String theNum) {
this.theNum = theNum;
}
public int convert() {
String a = String.valueOf(theNum);
String[] b = a.split("\\.");
String b2 = b[1];
int zeros = b2.length();
String num = "1";
for(int x = 0; x < zeros; x++) {
num += "0";
}
float c = Float.parseFloat(theNum);
int multiply = Integer.parseInt(num);
float answer = c - (int)c;
int integerForm = (int)(answer * multiply);
return integerForm;
}
}
Then within your main class:
public class ChapterOneBasics {
public static void main(String[] args) throws java.io.IOException{
NumConvert n = new NumConvert("123.456");
NumConvert q = new NumConvert("123.45600128");
System.out.println(q.convert());
System.out.println(n.convert());
}
}
output:
45600128
456
Float or Double are imprecise, just an approximation - without precision. Hence 12.345 is somewhere between 12.3449... and 12.3450... .
This means that 12.340 cannot be distinghuished from 12.34. The "decimal part" would be 34 divided by 100.
Also 12.01 would have a "decimal part" 1 divided by 100, and too 12.1 would have 1 divided by 10.
So a complete algorith would be (using java):
int[] decimalsAndDivider(double x) {
int decimalPart = 0;
int divider = 1;
final double EPS = 0.001;
for (;;) {
double error = x - (int)x;
if (-EPS < error && error < EPS) {
break;
}
x *= 10;
decimalPart = 10 * decimalPart + ((int)(x + EPS) % 10);
divider *= 10;
}
return new int[] { decimalPart, divider };
}
I posted the below solution yesterday after testing it for a while, and later found that it does not always work due to problems regarding precision of floats, doubles and bigdecimals. My conclusion is that this problem is unsolvable if you want infinite precision:
So I re-post the code just for reference:
fun getDecimalCounter(d: Double): Int {
var temp = d
var tempInt = Math.floor(d)
var counter = 0
while ((temp - tempInt) > 0.0 ) {
temp *= 10
tempInt = Math.floor(temp)
counter++
}
return counter
}
fun main(args: Array <String> ) {
var d = 3.14159
if (d < 0) d = -d
val decimalCounter = getDecimalCounter(d)
val decimalPart = (d - Math.floor(d))
var decimalPartInt = Math.round(decimalPart * 10.0.pow(decimalCounter))
while (decimalPartInt % 10 == 0L) {
decimalPartInt /= 10
}
println(decimalPartInt)
}
I dropped floats because of lesser precision and used doubles.
The final rounding is also necessary due to precision.

How to get the value which is after the point

How to get the value which is after the point.
Example:
If 5.4 is the value and I want to get the value 4 not 0.4, how can I do this?
You can use String functions for that :
public static void main(String args[]){
Double d = 5.14;
String afterD = String.valueOf(d);
afterD =afterD.substring(afterD.indexOf(".") + 1);
System.out.println(afterD);
}
first of all convert number to String,
Then using Substring get indexof(".") + 1 then print it.
& see it ll work.
OR You can try :
double d = 4.24;
BigDecimal bd = new BigDecimal(( d - Math.floor( d )) * 100 );
bd = bd.setScale(4,RoundingMode.HALF_DOWN);
System.out.println( bd.intValue() );
will print : 24
suppose your input is 4.241 then you have to add 1 extra 0 in BigDecimal bd formula i.e. instead of 100 it ll be 1000.
Code:
double i = 5.4;
String[] s = Double.toString(i).split("\\.");
System.out.println(s[1]);
output:
4
Explantion:
you can convert the double to String type and after that use split function which split the converted double to String in two pieces because of using \\. delimiter. At the end, type out the second portion that you want.
you can try this
code:
double i = 4.4;
String s = Double.toString(i);
boolean seenFloatingPoint = false;
for (int j = 0; j < s.length(); j++) {
if(s.charAt(j)== '.' && !seenFloatingPoint){
seenFloatingPoint = true;
} else if (seenFloatingPoint)
System.out.print(s.charAt(j));
}
System.out.println("");
output:
4
the one line answer is
int floatingpoint(float floating){
return Integer.valueOf((Float.toString(floating).split(".")[1]));
}
which will do as follows:
convert the number e.g 56.45 to string
then split the string in string array where [0]="56" and [1]="45"
then it will convert the the second string into integer.
Thanks.
Try this way
Double d = 5.14;
String afterD = String.valueOf(d);
String fractionPart = afterD.split("\\.")[1];
Try this way
double d = 5.24;
int i = Integer.parseInt(Double.toString(d).split("\\.")[1]);
int i=(int)yourvalue;
float/double afterDecimal= yourvalue - i;
int finalValue = afterDecimal * precision;//define precision as power of 10
EX. yourvalue = 2.345;
int i=(int)yourvalue;//i=2
float/double afterDecimal= yourvalue - i;//afterDecimal=0.345
int finalValue = afterDecimal * precision;
//finalValue=0.345*10 or
//finalValue=0.345*100 or
// finalValue=0.345*1000
...
System.out.println((int)(5.4%((int)5.4)*10));
Basically 5.4 mod 5 gets you .4 * 10 gets you 4.

Creating 0.000.. with certain decimals

I am trying to create the number 0.00000.... with as many '0' as the user input wants. What is wrong with my code below?
int n;
double dec = 0.0;
in = new Scanner(System.in);
n = in.nextInt();
for (i = 1; i <= n; i++)
dec = dec / 10.0d;
Number doesn't change.
You're expecting double to retain the number of decimal digits - it doesn't do that. The value is always normalized. The double type is all about the magnitude of a number, not a particular decimal representation. It's suitable for naturally occurring quantities - weights, heights etc.
If you care about decimal digits, then BigDecimal is a more suitable type for you. This is more appropriate for currency values for example, where there really is a precise amount specified as a decimal representation.
BigDecimal does retain the number of decimal digits you use, but you'll need to be careful about exactly how you use it. You'll no doubt find the setScale method useful.
For example:
import java.math.BigDecimal;
class Test {
public static void main(String[] args) throws Exception {
BigDecimal x = new BigDecimal("0")
System.out.println(x); // 0
x = x.setScale(5);
System.out.println(x); // 0.00000
}
}
If you just want to display the decimal point according to user input, Try
int n;
double dec = 0.0;
in = new Scanner(System.in);
n = in.nextInt(); //number of decimal places
System.out.println(String.format("%."+n+"f",dec));
0.0, 0.00, 0.0000000000000000000000000000000000000000000000 and so on are exactly the same value; Java literally can't tell them apart during runtime. No matter how many times you divide it by 10, it will remain EXACTLY the same number.
When being printed, trailing zero digits are omitted (unless explicitly specified in, for instance, String.format).
Basically, what you are trying to do is keep on dividing 0.0. But it'll always give you the same result as Java considers 0.000 as 0.0. Even 0.0000000000000000 will be considered as 0.0. If you just want to display that many 0s, then save it in a String and then display.
...
StringBuilder s = new StringBuilder("0.");
for(int i = 1; i < n; i++)
s.append("0");
String num = s.toString();
//Then use it.
If you need string with user defined '0':
public static String FormatZero( int accurancy_ ) throws IllegalArgumentException
{
if( 0 >= accurancy_ )
{
throw new IllegalArgumentException( "accurancy_must be > 0" );
}
String formatString = "0.";
for( int i = 0 ; i < accurancy_ ; ++i )
{
formatString += "0";
}
DecimalFormat format = new DecimalFormat( formatString );
String result = format.format( 0d );
return result;
}

Determine Number of Decimal Place using BigDecimal

I was interested to have the following getNumberOfDecimalPlace function:
System.out.println("0 = " + Utils.getNumberOfDecimalPlace(0)); // 0
System.out.println("1.0 = " + Utils.getNumberOfDecimalPlace(1.0)); // 0
System.out.println("1.01 = " + Utils.getNumberOfDecimalPlace(1.01)); // 2
System.out.println("1.012 = " + Utils.getNumberOfDecimalPlace(1.012)); // 3
System.out.println("0.01 = " + Utils.getNumberOfDecimalPlace(0.01)); // 2
System.out.println("0.012 = " + Utils.getNumberOfDecimalPlace(0.012)); // 3
May I know how can I implement getNumberOfDecimalPlace, by using BigDecimal?
The following code doesn't work as expected:
public static int getNumberOfDecimalPlace(double value) {
final BigDecimal bigDecimal = new BigDecimal("" + value);
final String s = bigDecimal.toPlainString();
System.out.println(s);
final int index = s.indexOf('.');
if (index < 0) {
return 0;
}
return s.length() - 1 - index;
}
The following get printed :
0.0
0 = 1
1.0
1.0 = 1
1.01
1.01 = 2
1.012
1.012 = 3
0.01
0.01 = 2
0.012
0.012 = 3
However, for case 0, 1.0, it doesn't work well. I expect, "0" as result. But they turned out to be "0.0" and "1.0". This will return "1" as result.
Combining Turismo, Robert and user1777653's answers, we've got:
int getNumberOfDecimalPlaces(BigDecimal bigDecimal) {
return Math.max(0, bigDecimal.stripTrailingZeros().scale());
}
stripTrailingZeros() ensures that trailing zeros are not counted (e.g. 1.0 has 0 decimal places).
scale() is more efficient than String.indexOf().
A negative scale() represents zero decimal places.
There you have it, the best of both worlds.
This code:
int getNumberOfDecimalPlaces(BigDecimal bigDecimal) {
String string = bigDecimal.stripTrailingZeros().toPlainString();
int index = string.indexOf(".");
return index < 0 ? 0 : string.length() - index - 1;
}
... passes these tests:
assertThat(getNumberOfDecimalPlaces(new BigDecimal("0.001")), equalTo(3));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("0.01")), equalTo(2));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("0.1")), equalTo(1));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1.000")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1.00")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1.0")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10.1")), equalTo(1));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10.01")), equalTo(2));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10.001")), equalTo(3));
... if that is indeed what you want. The other replies are correct, you have to use BigDecimal all the way through for this rather than double/float.
Without having to convert to String, it should be more efficient to use the scale directly:
private int getNumberOfDecimalPlaces(BigDecimal bigDecimal)
{
int scale = bigDecimal.stripTrailingZeros().scale();
return scale>0?scale:0;
}
That should do it
int getNumberOfDecimalPlace(BigDecimal number) {
int scale = number.stripTrailingZeros().scale();
return scale > 0 ? scale : 0;
}
If you really get doubles i recommend formating them first as strings before creating the BigDecimal. At least that has worked for me: How to check if a double has at most n decimal places?
Depending on how many digits you expect you can either use standard formating like
String.valueOf(doubleValue);
or you could use specialised formatting to avoid exponential format
DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
// don't use grouping for numeric-type cells
decimalFormat.setGroupingUsed(false);
decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
value = decimalFormat.format(numericValue);
When you have a BigDecimal you can simply call scale() to get the number of decimal places.
It's not your code that's wrong, but your expectations. double is based on a binary floating point representation and completely unfit for accurately representing decimal fractions. Decimal 0.1 e.g. has an infinite number of digits when represented in binary, thus it gets truncated and when converted back to decimal, you get erros in the least significant digits.
If you use BigDecimal exclusively, your code will work as expected.
Try this:
Math.floor(Math.log(x) / Math.log(10))
0.001 = -3
0.01 = -2
0.1 = -1
1 = 0
10 = 1
100 = 2
How about having a look at the javadoc of BigDecimal. I'm not sure, but I'd give getScale and getPercision a try.
The best way to get a BigDecimal with a specified number of decimal places is by using the setscale method over it. Personally I like to also use the rounding version of the method (see the link below):
http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html#setScale(int,%20int)
If you're wanting to get the number of decimal positions that a BigDecimal is currently set at call the associated scale() method.
Best option I have found so far (not needing toString + index):
public static int digitsStripTrailingZero(BigDecimal value)
{
return digits(value.stripTrailingZeros());
}
public static int digits(BigDecimal value)
{
return Math.max(0, value.scale());
}
Michael Borgwardt answer is the correct one. As soon as you use any double or float, your values are already corrupted.
To provide a code example:
System.out.println("0 = " + BigDecimalUtil.getNumberOfDecimalPlace("0")); // 0
System.out.println("1.0 = " + BigDecimalUtil.getNumberOfDecimalPlace("1.0")); // 0
System.out.println("1.01 = " + BigDecimalUtil.getNumberOfDecimalPlace(new BigDecimal("1.01"))); // 2
System.out.println("1.012 = " + BigDecimalUtil.getNumberOfDecimalPlace(new BigDecimal("1.012"))); // 3
System.out.println("0.01 = " + BigDecimalUtil.getNumberOfDecimalPlace("0.01")); // 2
System.out.println("0.012 = " + BigDecimalUtil.getNumberOfDecimalPlace("0.012")); // 3
System.out.println("0.00000000000000000012 = " + BigDecimalUtil.getNumberOfDecimalPlace("0.00000000000000000012")); // 20
And an overloaded version of getNumberOfDecimalPlace so you could use it with BigDecimal or String:
public static int getNumberOfDecimalPlace(String value) {
final int index = value.indexOf('.');
if (index < 0) {
return 0;
}
return value.length() - 1 - index;
}
public static int getNumberOfDecimalPlace(BigDecimal value) {
return getNumberOfDecimalPlace(value.toPlainString());
}
Why not just change your code to get a doubles decimal places?
public static int getNumberOfDecimalPlace(double value) {
//For whole numbers like 0
if (Math.round(value) == value) return 0;
final String s = Double.toString(value);
System.out.println(s);
final int index = s.indexOf('.');
if (index < 0) {
return 0;
}
return s.length() - 1 - index;
}

Categories