How to check number of digits from BigDecimal? - java

The requirement is to check if the number of digits is less than 7 digits in that case insert in DB else don't. I have tried the following solutions:
First solution:
public static void checkNoOfDigitVal(BigDecimal bigDecVal) {
BigInteger digits = bigDecVal.toBigInteger();
BigInteger ten = BigInteger.valueOf(10);
int count = 0;
do {
digits = digits.divide(ten);
count++;
} while (!digits.equals(BigInteger.ZERO));
System.out.println("Number of digits : " + count);
}
First solution works fine sometimes but sometimes the condition in while loop is not satisfied and it keeps on increasing the count number leading to endless count.
Second solution:
public static void checkNoOfDigitsVal(BigDecimal bigDecVal) {
String string = bigDecVal.toString();
String[] splitedString = string.split("\\.");
String[] newVal = splitedString[0].split("");
int a = newVal.length - 1;
if (a <= 6) {
System.out.println("correct size insert into DB: " + a);
} else {
System.out.println("Incorrect size insert cancel: " + a);
}
}
For example, if the value is 999999.9999, the second solution will return newVal.length = 6.
Please suggest a better solution to check the number of digits for big decimal where looping overhead can be minimized.

You can get it trivially using:
static int integerDigits(BigDecimal n) {
n = n.stripTrailingZeros();
return n.precision() - n.scale();
}
The precision is the total number of digits, and the scale is how many of those are to the right of the decimal point, so the difference is how many are to the left of the decimal point.
EDIT it's necessary to remove any trailing zeros to get a correct result for e.g. 0.000
EDIT 2 alternatively (and acks to #AdrianShum), since the problem with trailing zeroes only manifests itself with 0.00... you could use:
static int integerDigits(BigDecimal n) {
return n.signum() == 0 ? 1 : n.precision() - n.scale();
}
Live demo at http://ideone.com/uI6iMG

There's a much better solution in Alnitak's answer, posted just after mine (but which I've only seen now). I guess I'll leave this since a couple of people have found it useful, but if I needed to do this, I'd use their approach, not the approach below.
Your second solution is close, but it doesn't have to be quite that complicated:
public static void checkNoOfDigitsVal(BigDecimal bigDecVal) {
String str = bigDecVal.toString();
int wholeNumberLength = str.split("\\.")[0].length();
if (wholeNumberLength <= 6) {
System.out.println("correct size insert into DB: " + wholeNumberLength);
} else {
System.out.println("Incorrect size insert cancel: " + wholeNumberLength);
}
}
Live Example
I'm assuming that your 999999.999 example should result in wholeNumberLnegth of 6 and therefore be inserted in the DB (the question is unclear about that).

Because the current answers are not robust enough IMO, Here's my solution.
This method will scale a BigDecimal to the given length, but only scales the fractional part. It will throw an Exception if the integer part will be scaled. For my use case this is what I want. Tweak it to your liking.
public static BigDecimal scaleBigDecimalToLength(BigDecimal bigDecimal, int length) throws NumbersUtilException {
int digitCount = bigDecimal.toPlainString().replaceAll("[.,-]", "").length();
if (digitCount > length) {
int scale = bigDecimal.scale();
int newScale = length - (digitCount - scale);
if (scale > 0 && newScale >= 0) {
bigDecimal = bigDecimal
.setScale(length - (digitCount - scale), RoundingMode.HALF_UP);
} else {
throw new NumbersUtilException(
String.format("Cannot scale %s to a length of %s", bigDecimal, length));
}
}
return bigDecimal;
}
scaleBigDecimalToLength(BigDecimal.valueOf(0.0000012345600000), 8)
Output: 0.0000012

If you want to ignore the Dot (".") and count. then try this :
int count = 0;
BigDecimal bigDecimal = new BigDecimal("123.1000");
String[] split = bigDecimal.toString()
.split("\\.");
for (String element : split) {
count = count + element.length();
}
System.out.println("Total digits are " + count);

Related

How does recursion work and how can recursion be used to manipulate integer digits?

I'm trying to learn java, and I can't seem to understand recursion. I can understand how recursion can be used to add and do other basic math operations but how can recursion be used to reverse manipulate integers and individual integer digits.
example:
a method takes a single positive integer argument and displays its base five equivalent. 231 returns 1411 but the code below returns 1141. how would I reverse the order of integers put out?
public void base5(int n){
int rem=n%5;
int vis=n/5;
if(n!=0){
// System.out.print(rem/*+"|"*/);
//
// rem=(rem+rem)*10;
// System.out.print("\n||"+n+"||\n");
System.out.print(rem);
base5(vis);
}
else{
return;
}
}
The algorithm for getting individual digits of an integer, from right to left, is well known. See How to get the separate digits of an int number?.
I won't "explain" recursion, but I'll give you one possible solution for first problem:
a method takes a single positive integer and displays it with commas
inserted every three digits
import java.util.Scanner;
class Main {
public static void main( String [] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter your positive integer: ");
long number = sc.nextLong();
String result = addCommas(number);
System.out.println(result);
}
public static String addCommas(long num) {
return addCommas(num, 1);
}
public static String addCommas(long num, int counter) {
if (num == 0) {
return ""; // base case ends recursion
}
else {
long digit = num % 10;
num = num / 10;
String comma = (counter%3==0 && num>0) ? "," : "";
// recursive call below because we call addCommas() again
return addCommas(num, counter+1) + comma + digit;
}
}
}
Here's a compact solution to the second problem:
a method takes a single positive integer and displays the result of
reversing its digits
public static String reverseDigits(long num) {
if (num == 0) {
return "";
}
else {
return String.valueOf(num % 10) + reverseDigits(num / 10);
}
}

How to leave only 4 decimals after number bigger than 0?

I don't know how to explain this well, but for example I have a number:
0.00000548347554 and want to make 0.000005483 from it, or
0.0683453248 to 0.06843, etc.
This assumes your number is a string:
String tmp = "0.0683453248";
String[] tmpA = tmp.split("");
ArrayList<String> res = new ArrayList<>();
for(int i = 0; i < tmpA.length; i++){
res.add(tmpA[i]);
if(!tmpA[i].equals(".") && Integer.parseInt(tmpA[i]) > 0){
res.add(tmpA[i + 1]);
res.add(tmpA[i + 2]);
res.add(tmpA[i + 3]);
break;
}
}
String result = String.join("",res);
Using the solution from this answer, you can convert the given number into a string and then use the regex replacement to get the required string out of it.
Demo:
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(doubleToString(0.00000548347554));
System.out.println(doubleToString(0.0683453248));
}
static String doubleToString(double n) {
DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340);
return df.format(n).replaceAll("(\\d*\\.0*[1-9]{4})\\d*", "$1");
}
}
Output:
0.000005483
0.06834
ONLINE DEMO
Explanation of the regex:
(: Start of capturing group#1
\\d*\\.: Digit(s) followed by .
0*: Any number of zeros
[1-9]{4}: Non-zero four digits
): End of capturing group#1
\d* : Any digit any number of times
For small numbers BigDecimal can be used:
BigDecimal significant(double number, int count) {
if (count < 1)
throw new IllegalArgumentException("invalid count: " + count);
BigDecimal big = BigDecimal.valueOf(number);
if (big.precision() <= count) {
return big;
} else {
return big.setScale(big.scale()-big.precision()+count, RoundingMode.HALF_EVEN);
}
}
precision() returns the number of significant digits;
the method changes the scale so only the desired number of digits is present.
The if is used to avoid more zeros than the input if this has less than count digits.
Use doubleValue() to convert the result to double if needed (may suffer from rounding error).
To get a string, use toPlainString(), which will transform the result to string without using the exponential notation.
Rounding mode can also be changed if desired.
Note: it can also be used with larger numbers, it basically will replace digits by zero like in significant(12345,2) -> 12000 (or 1.2E+4)

Why am I getting the error in a loop that reoccurs at a single particular iteration every run-time? (Binary Queries problem from HackerEarth)

I'm trying to solve this question:
Binary Queries,
https://www.hackerearth.com/practice/data-structures/arrays/1-d/practice-problems/algorithm/range-query-2/
Question summary:
N digits of binary numbers are given; Q queries are then given.
Two types of queries:
"0 X": Flip the Xth bit
"1 L R": Print if binary no. formed by L to R(position) is odd or even.
Simple solution is to check only rightmost bit; if it's 1, the number is odd, else, even.
My code throws "Wrong answer" every time;
however, IN ALL TEST CASES, there's ONLY ONE wrong output, and this wrong output happens EXACTLY 99 lines before the total number of output lines*.
There seems to be no other pattern.
*I tried flipping output when I reach (Q-99)th query to check; however, there's no way to find number of output queries without storing all queries, since query type[0] has no output, only type1 has an output. Thus, Q cannot be used.
Images: All testcases fail Eg.1 The only line of error Eg.2 Another example.
Here's my code:
public static void main(String args[]) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inpArr[] = (br.readLine().split("\\s"));
int n=Integer.parseInt(inpArr[0]); //number of digits
int q=Integer.parseInt(inpArr[1]); //number of queries
//read binary digits w/o space, and store them as chars
String binArrStr=br.readLine().replace(" ","");
char[] binArr=binArrStr.toCharArray();
int i;
for(i=0;i<q;i++) //all queries
{
String query[]=br.readLine().split("\\s"); //read the query
if(query[0].equals("1")) //Flip the bit if query[0]=1
{
if(binArr[Integer.parseInt(query[1])-1]=='1') //take position(query[1]) as int and flip
binArr[Integer.parseInt(query[1])-1]='0';
else
binArr[Integer.parseInt(query[1])-1]='0';
}
else //Print odd or even if query[0]=0
{
//query[1] is leftmost bit.
//Sufficient to check only the bit in rightmost position, given by
//3rd argument(Rightmost bit) which is query[2]
//If rightmost bit==1, ODD, else EVEN
if(binArr[Integer.parseInt(query[2])-1]=='1')
System.out.println("ODD");
else
System.out.println("EVEN");
}
}
}
I could skip this problem, but it's better to know why exactly this happens, I think.
if(query[0].equals("1")) //Flip the bit if query[0]=1
{
if(binArr[Integer.parseInt(query[1])-1]=='1') //take position(query[1]) as int and flip
binArr[Integer.parseInt(query[1])-1]='0';
else
binArr[Integer.parseInt(query[1])-1]='0';
}
in your if statement you checked that if it's 1 then flip it to 0 but in your else block you are not flipping the number to 1 because else block will come to action if the number is 0. Hence you are only partially flipping.
Here is my solution
import java.util.Scanner;
class TestClass {
public static void main(String args[]) throws Exception {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int q = scan.nextInt();
int[] bits = new int[n + 1];
for (int i = 1; i <= n; i++) {
bits[i] = scan.nextInt();
}
for (int i = 1; i <= q; i++) {
if (scan.nextInt() == 1) {
int index = scan.nextInt();
if (bits[index] == 0) bits[index]++;
else bits[index]--;
} else {
int lIndex = scan.nextInt();
int rIndex = scan.nextInt();
System.out.println(bits[rIndex] == 0 ? "EVEN" : "ODD");
}
}
}
}

Flipping binary numbers using recursion

I am working on a project that the user enters an odd binary number ex: 10101 and I am supposed to have a recursive method that will flip the 1's and 0's ex: 101 = 010. For some reason my code is getting rid of the leading zero making the number an even number which crashes the program. Any and all help is appreciated, below is my Recursive class that is supposed to do the work of flipping the binary digits.
public class Recursive2 {
// int digit;
String temp;
public Recursive2(int d){
//digit = d;
temp = recursive(Integer.toString(d));
//System.out.print(recursive(temp));
}
public String toString(){
return temp;
}
public String recursive(String a){
String tempStr = "";
if(a.length() % 2 == 0){
System.out.println("Even number");
return "";
}
else if(a.length() == 1){
if(a.equals("1")){
tempStr = "0";
// tempStr += d;
}
else if(a.equals("0")){
tempStr= "1";
}
//System.out.println("Flipped d to" + tempStr);
}
else{
tempStr += new Recursive2(Integer.parseInt(a.substring(0,1))).toString();
tempStr += new Recursive2(Integer.parseInt(a.substring(1, a.length() - 1))).toString();
tempStr += new Recursive2(Integer.parseInt(a.substring(a.length()-1, a.length()))).toString();
}
return tempStr;
}
Here is my main class that tests the recursion.
public static void main(String[] args){
String num;
Scanner in = new Scanner(System.in);
System.out.println("Please enter a Binary number with an odd amount of digits: ");
num = in.nextLine();
System.out.println(num);
int num2 = Integer.parseInt(num);
System.out.println(num2);
Recursive2 test = new Recursive2(num2);
System.out.println(test);
}
You made several mistakes:
Deciding if the number is odd or even should be done before calling recursive method. Currently, your code will stop after at most one invocation, because you check the number of bits.
There is no need to parse int and making it String again. The entire process can be done entirely with strings.
Constructing the result should consist of appending the result of recursive invocation without the last bit to the string representing the inverse of the last bit.
The base case should be a situation when the string is empty, not when the string has exactly one digit.
Fixing these mistakes will produce a correct implementation.
The current algorithm is beyond repair.
Here's a recursive algorithm that's very simple and that will work:
if the string is empty, return it
if the first char is 0, return "1" + recurse(s.substring(1))
otherwise (the first char is 1), return "0" + recurse(s.substring(1))
Leading zeros are ignored because you're converting the input binary number to integer. For an integer leading zeros don't mean anything. You should be working with String only.
Also Integer.parseInt(num); would assume that you want to parse a decimal number not binary. If you do want to parse a binary number then you'll have to use another overloaded method Integer.parseInt(String s, int radix)
However as I said, because of the leading zeros you should work only with the Strings.
Integer.parseInt(i) converts the String to its Integer value.
However the Integer value of 010 is 10, leading 0's are dropped.
Work with the input as a String to avoid this.
Use StringBuilder to avoid creating new String or you can use char array
public static void main(String[] args) {
int no = 1234; // some no
String in = Integer.toBinaryString(no);
System.out.println("Original " + in);
System.out.println("Flipped " + flipBits(in));
}
public static String flipBits(String in) {
if (in.length() % 2 == 0)
return "even length";
return new String(flipBits(in.toCharArray(), in.length() - 1));
}
private static char[] flipBits(char[] ch, int index) {
if (index < 0) {
return ch;
} else {
ch[index] = Character.forDigit(49 - ch[index], 2); //flip
return flipBits(ch, index - 1);
}
}
output
Original 10011010010
Flipped 01100101101
The problem is that you are converting to integer values, which will throw away leading zeros. Just deal with strings:
public static void main(String[] args){
String num;
Scanner in = new Scanner(System.in);
System.out.println("Please enter a Binary number with an odd amount of digits: ");
num = in.nextLine();
System.out.println(num);
String flipped;
if (num.length() % 2 == 0) {
flipped = "Even number";
else {
flipped = Recursive2.recursive(num);
}
System.out.println(flipped);
}
And the Recursive2 class can just have static methods:
public class Recursive2 {
private static String flip(char c) {
if (c == '0') return "1";
return "0"; // assumes characters are all 0 or 1
}
public static String recursive(String a) {
STring tempStr;
if (a.length() == 0) {
tempStr = "";
} else {
tempStr = flip(a.charAt(0)) + recursive(a.substring(1));
}
return tempStr;
}
}
You might want to throw an exception if you detect a character other than 0 or 1.
EDIT: Based on your comment, the recursive method can be written as:
public static String recursive(String a) {
String tempStr = flip(a.charAt(0));
final int len = a.length();
if (len > 1) {
tempStr += recursive(a.substring(1, len - 1)) + flip(a.charAt(len - 1));
}
return tempStr;
}
This assumes that the argument is an odd-length string. That check should be done outside the recursive method, since if it is true once, it is true at every subsequent recursion.
I'd advise you to instead, remove one digit from the String that the user has imputed, and convert it (from the 1 to 0 vise versa), then use sub-string as the pass for the recursive function with one less.
Hint-> the base case would be a.length() == 0; because if you remove one digit of the string you will eventually have the length be 0.
Good Luck!

java.io.StreamTokenizer.TT_NUMBER: Floating or Integer?

is there a way to find if the value parsed and returned by java.io.StreamTokenizer.nval (e.g. 200) was an integer or a floating number ?
Thanks
Edited:
I want to be able to know if the input was '200' or '200.0'.
I don't think it is possible with StringTokenizer, it's too old. You can use Scanner to do the job:
Scanner fi = new Scanner("string 200 200.0");
fi.useLocale(Locale.US);
while (fi.hasNext()) {
if (fi.hasNextInt()) {
System.out.println("Integer: " + fi.nextInt());
} else if (fi.hasNextDouble()) {
System.out.println("Double: " + fi.nextDouble());
} else {
System.out.println("String: " + fi.next());
}
}
Documentation for the class is here
As you are essentially trying to figure out if a double is an int or not, you can create a BigDecimal and test its scale() method. You could also use the Math static method floor() and test the return value against the original.
if(Math.floor(myStreamTokenizer.nval) == myStreamTokenizer.navl)) {
//treat it as an int
} else {
//treat it as a double
}
Of the two, I would use the Math.floor option, as it would be more efficient.
I would use the modulus operator:
if (yourNval % 1 > 0)
{
// nval is floating point.
}
else
{
// nval is an integer.
}
This works because modulus works with floating point numbers in Java as well as integers.
UPDATE: Since you specify a need to distinguish integers from doubles with zero-value decimal portions, I think you'll have to do something like the following:
Double(yourNval).toString().indexOf('.');
So a more-complete function will look like:
if (yourNval % 1 > 0)
{
// nval is floating point.
}
else
{
// nval is an integer.
// Find number of trailing zeroes.
String doubleStr = Double(yourNval).toString();
int decimalLoc = doubleStr.indexOf('.');
int numTrailingZeroes = 0;
if (decimalLoc > 0)
{
numTrailingZeroes = doubleStr.length() - decimalLoc - 1;
}
}

Categories