This question already has answers here:
How to convert a Binary String to a base 10 integer in Java
(12 answers)
Closed 4 years ago.
Main:
public class Main{
public static void main(String[] args){
System.out.println(Convert.BtoI("101101010101"));
System.out.println(Convert.BtoI("1011110"));
}
}
Sub:
public class Convert{
public static int BtoI(String value){
int no = 0;
for(int i=value.length()-1;i>=0;i--){
if(value.charAt(i)=='1')
no += (???) ;
++;
}
return no;
}
}
How can I convert a string binary to integer without using maths.pow, just using + - * and /, should I implement another for loop for it is int j = 1;i <= example; i*=2){ ?. I am quite confused and want to learn without the usage of maths.pow or any similar codes.
From the beginning of the string until to the end you can just multiply each character with its power and sum up the total which gives you the base ten value:
public static int binaryToInt(String binaryNum) {
int pow = 1;
int total = 0;
for (int i = binaryNum.length(); i > 0; i--) {
if (binaryNum.charAt(i-1) == '1') {
total += pow;
}
pow *= 2;
}
return total;
}
But i think this is way more elegant:
String binaryNum = "1001";
int decimalValue = Integer.parseInt(binaryNum, 2);
How about Integer.parseInt(yourString,2); ?? 2 means you are parsing base2 number.
Starting from your code + some vital style changes:
public class Convert {
public static int binaryToInt(String value) {
int no = 0;
for (int i = 0; i < value.length() - 1; i++) {
no = no * 2; // or no *= 2;
if (value.charAt(i) == '1') {
no = no + 1; // or no++
}
}
return no;
}
}
The meaning of the code I added should be self-evident. If not, I would encourage you to work out what it does as an exercise. (If you are not sure, use a pencil and paper to "hand execute" it ...)
The style changes (roughly in order of importance) are:
Don't start a method name with an uppercase character.
Use camel-case.
Avoid cute / obscure / unnecessary abbreviations. The next guy reading your code should not have to use a magic decoder ring to understand your method names.
Put spaces around operators.
4 character indentation.
Put spaces between ) and { and before / after keywords.
Use curly brackets around the "then" and "else" parts of an if statement, even if they are not strictly necessary. (This is to avoid a problem where indentation mistakes cause you to misread the code.)
Related
I recently gave a codility test. There was a this question which I couldn't solve. Now that I'm trying at home, I would like to get help. I don't remember the complete question language, but I do remember the output how would the program respond. Here we go.
"write a java program, for a given number N, need to find the lowest number for the given N. N could be a billion number too."
{this may not be the exact one, Sorry about that}
For Example:
N=1 then o/p is 0.
N=123 then o/p is 100
N=1234 then o/p is 1000 and so on.
My Solution: --just a workaround, this isn't actual logic.
class Solution {
public int solution(int N) {
int pointer=0;
if (N == 1) {
return 0;
} else {
String digitsCount = Integer.toString(N);
for(int i = 0; i < digitsCount.length(); i++) {
pointer++;
}
StringBuffer subString = new StringBuffer();
int count=0;
while(count < pointer-1) {
subString.append("0");
count++;
}
subString = subString.insert(0, "1");
return Integer.parseInt(subString.toString());
}
}
}
Using math library, should be good for about 16 digits.
long getLow(long in) {
if (in <= 1) return 0; // see note below
return (long)(Math.pow(10, Math.floor(Math.log10(in))));
}
The calculation is undefined for in < 1; we return 0. For in = 1 we return 0 per original code, though returning 1 would surely be more consistent: 2,3,...9 return 1, so why not 1 returns 1?
Your solution seems to work fine. The only thing it doesn't take into account is the fact that N can be a very large number. int only has a max value of about 2 billion.
Here is my solution:
public static long getLowestNumberWithSameNumberOfDigits(long input) {
if (input < 10) { // special case
return 0;
}
long trial = 10;
while (input / trial >= 10) {
trial *= 10;
}
return trial;
}
Thank You! Guys. All the suggestions were helpful. Infact, every suggestion has a learning. Here is the updated code. Please accept if you think its good enough.
private static long solution(long N) {
if (N == 1) {
return 0;
} else {
String digitsCount = Long.toString(N);
int pointer=digitsCount.length();
StringBuilder subString = new StringBuilder();
subString.append("1");
for(int i=0; i<pointer-1; i++) {
subString.append("0");
}
return Long.parseLong(subString.toString());
}
}
I have the correct code, I found an answer long ago, however I still don't understand why it works.
class Main {
public static void main(String[] args) {
System.out.println(D5PSum(10));
}
private static int D5PSum(int number) {
String n = Integer.toString(number);
int sum = 0;
for (int i = 0; i < n.length(); i++) {
// (1) WHY DOES THIS NOT WORK
//sum += Integer.parseInt(number.charAt(i));
// (2) MORE IMPORTANTLY WHY DOES THIS WORK
char c = n.charAt(i);
sum += (c-'0');
// (3) WHAT IN THE WORLD IS c-'0'
}
return sum;
}
}
// (1) WHY DOES THIS NOT WORK
because Integer.parseInt(...); is expecting a string as parameter not a char
// (2) MORE IMPORTANTLY WHY DOES THIS WORK
char c = n.charAt(i);
any char is nothing else as an integer mapped to a table of symbols...(ASCII table for example) so this (c - '0') is just another valid mathematical operation
charAt is not a valid method of the primitive type int.
'0' is the character 0, and the character encoding set that Java uses has 0 to 9 in a consecutive block. Therefore c - '0' yields the position of c in that consecutive block which is therefore the value of the digit. (Actually this sort of thing is idiomatic C - goes right back to the 1960s).
You should first convert String to Int.. Please check the below code:
class MainClass {
public static void main(String[] args) {
System.out.println(D5PSum(11));
}
private static int D5PSum(int number) {
String n = Integer.toString(number);
System.out.println(n);
int sum = 0;
for (int i = 0; i < n.length(); i++) {
// (1) WHY DOES THIS NOT WORK
String str = String.valueOf(n.charAt(i));
sum += Integer.parseInt(str);
// (2) MORE IMPORTANTLY WHY DOES THIS WORK
// char c = n.charAt(i);
// sum += (c-'0');
// (3) WHAT IN THE WORLD IS c-'0'
}
return sum;
}
}
1
It doesnt work because Integer.parseInt takes a String and String.charAt returns a char(actar). Integer.parseInt (Character.toString(n.charAt(i))) would Work.
2/3
A char represents a number between 0 and 65535. EACH digit-characters (0-9) has a number in that range which depends on the charset. All digits are typically in a row, for example the character 0 has the value 48, 1 49 and 9 57. So ich you want to know the digit value of a char you simply subtract the character value of 0 from your character. That is the Line c-'0'
// (1) WHY DOES THIS NOT WORK
//sum += Integer.parseInt(number.charAt(i));
number is a variable of primitive data type "int" so number.charAt(i) won't work.
// (2) MORE IMPORTANTLY WHY DOES THIS WORK
char c = n.charAt(i);
n is an instance of String and we are getting the character at i th position in the n string
sum += (c-'0');
// (3) WHAT IN THE WORLD IS c-'0'
for every character there is an ascii code assigned. '0' = 48, 'c' = 99. That's the reason why it works here. when 'c'-'0' is executed, it's equivalent to 99-48
Why convert to a string in the first place? The simplest and fastest way to solve this is without deviation to strings:
private static int D5PSum(int number) {
int v = number, sum = 0;
while (v != 0) {
sum += v % 10;
v /= 10;
}
return sum;
}
If you want your code (the part which does not works to work then do this).
class Main {
public static void main(String[] args) {
System.out.println(D5PSum(10));
}
private static int D5PSum(int number) {
String n = Integer.toString(number);
int sum = 0;
for (int i = 0; i < n.length(); i++) {
sum += Integer.parseInt(n.charAt(i)+"");
}
return sum;
}
}
To get sum of the digits of a string str:
int sum = str.chars().map(Character::getNumericValue).sum();
Fixing up and tidying the converter when I noticed that it somehow gives out incorrect conversions.
For example, when creating a new number to convert using BinaryNumber bn1 = new BinaryNumber("1011"); and then asking it to give out a result with System.out.println(bn1.convertToDecimal()); it prints out 3 instead of the correct result of 11.
I'm almost sure I got the actual conversion wrong but going through it in my head I can't find the mistake.
public class BinaryNumber {
private String n;
public BinaryNumber(String pn) {
n = pn;
}
public String getN() {
return n;
}
// Creating the .convertToDecimal()
public int convertToDecimal() {
int bitPosition = 0;
int sum = 0;
for (int i = n.length() - 1; i >= 0; i--) {
sum = sum + (int) Math.pow(2, bitPosition) * (n.charAt(i) - 48);
}
return sum;
}
// Creating the .add to add the two different binary numbers after
// converting
public int add(BinaryNumber bn2) {
return convertToDecimal() + bn2.convertToDecimal();
}
// Creating the .sub to subtract the two different binary numbers after
// converting
public int sub(BinaryNumber bn2) {
return convertToDecimal() - bn2.convertToDecimal();
}
}
You just need to increment your bitposition variable.
int bitPosition = 0;
int sum = 0;
for (int i = n.length() - 1; i >= 0; i--) {
sum = sum + (int) Math.pow(2, bitPosition++) * (n.charAt(i) - 48);
}
return sum;
First of all, Java has a built in binary system, using the primitive int type. You can use this by putting 0b before the number in binary form.
If you are doing this for learning purposes, then here's what's happening:
On each iteration, the value of bitPosition is always 0, because you never update it. Of course, you want to increase it with each iteration. This can be done simply by changing
Math.pow(2, bitPosition)
to
Math.pow(2, bitPosition++)
with the ++ after the variable to change it after it is referenced.
I need to write a program that can convert bits into decimal. Whenever I enter a bit, it only outputs 0.0. I cannot figure out why. I know it's incredibly simple but I am just not seeing it. Any help would be appreciated.
import java.lang.Math;
import java.util.Scanner;
public class Lab1 {
static double number = 0;
public static double toDec(String num) {
char[] charArray = num.toCharArray();
for(int i = 0; i<charArray.length;i++) {
if(charArray[i] == 1) {
number = Math.pow(2, charArray.length-i);
}
}
return number;
}
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int bit;
String bitString;
System.out.println("Please enter a bit");
bit = keyboard.nextInt();
bitString = Integer.toString(bit);
System.out.println(toDec(bitString));
}
}
You have compared charArray[i] to 1, but you're comparing apples to oranges, specifically, a char to an int.
Compare to the char '1' instead.
if(charArray[i] == '1') {
Also, you can make number a local variable in toDec; it doesn't need to exist outside that method.
In addition, this will only work if one bit is set. Right now you are working with one bitonly, but if you want to modify this to work with multiple bits, another changes is needed.
You overwrite number each time toDec is called and the condition is true. You will probably want to add to number with += instead of overwriting the previous value with =.
Integer#parseInt(String str, int radix) does the job :
public static Integer toDec(String num) {
return Integer.parseInt(num, 2);
}
So if you want to take the String "110011" which is 51. For big-endian you are going to have to determine how many bits to process. So if you read the string and it is 6 digits long then you know the first bit has to be shifted 6 places to the left.
int l = 6;
long value = 0;
for( int i = 0; i < l; i++ )
{
int bit = ( charArray[i] == "1" ) ? 1 : 0;
l = l + ( bit << l-i );
}
For float you would basically have to build an interpreter to decode the bits based on however the float is represented in binary.
What is the most efficient way to split a string by a very simple separator?
Some background:
I am porting a function I wrote in C with a bunch of pointer arithmetic to java and it is incredibly slow(After some optimisation still 5* slower).
Having profiled it, it turns out a lot of that overhead is in String.split
The function in question takes a host name or ip address and makes it generic:
123.123.123.123->*.123.123.123
a.b.c.example.com->*.example.com
This can be run over several million items on a regular basis, so performance is an issue.
Edit: the rules for converting are thus:
If it's an ip address, replace the first part
Otherwise, find the main domain name, and make the preceding part generic.
foo.bar.com-> *.bar.com
foo.bar.co.uk-> *.bar.co.uk
I have now rewritten using lastIndexOf and substring to work myself in from the back and the performance has improved by leaps and bounds.
I'll leave the question open for another 24 hours before settling on the best answer for future reference
Here's what I've come up with now(the ip part is an insignificant check before calling this function)
private static String hostConvert(String in) {
final String [] subs = { "ac", "co", "com", "or", "org", "ne", "net", "ad", "gov", "ed" };
int dotPos = in.lastIndexOf('.');
if(dotPos == -1)
return in;
int prevDotPos = in.lastIndexOf('.', dotPos-1);
if(prevDotPos == -1)
return in;
CharSequence cs = in.subSequence(prevDotPos+1, dotPos);
for(String cur : subs) {
if(cur.contentEquals(cs)) {
int start = in.lastIndexOf('.', prevDotPos-1);
if(start == -1 || start == 0)
return in;
return "*" + in.substring(start);
}
}
return "*" + in.substring(prevDotPos);
}
If there's any space for further improvement it would be good to hear.
Something like this is about as fast as you can make it:
static String starOutFirst(String s) {
final int K = s.indexOf('.');
return "*" + s.substring(K);
}
static String starOutButLastTwo(String s) {
final int K = s.lastIndexOf('.', s.lastIndexOf('.') - 1);
return "*" + s.substring(K);
}
Then you can do:
System.out.println(starOutFirst("123.123.123.123"));
// prints "*.123.123.123"
System.out.println(starOutButLastTwo("a.b.c.example.com"));
// prints "*.example.com"
You may need to use regex to see which of the two method is applicable for any given string.
I'd try using .indexOf("."), and .substring(index)
You didn't elaborate on the exact pattern you wanted to match but if you can avoid split(), it should cut down on the number of new strings it allocates (1 instead of several).
It's unclear from your question exactly what the code is supposed to do. Does it find the first '.' and replace everything up to it with a '*'? Or is there some fancier logic behind it? Maybe everything up to the nth '.' gets replaced by '*'?
If you're trying to find an instance of a particular string, use something like the Boyer-Moore algorithm. It should be able to find the match for you and you can then replace what you want.
Keep in mind that String in Java is immutable. It might be faster to change the sequence in-place. Check out other CharSequence implementations to see what you can do, e.g. StringBuffer and CharBuffer. If concurrency is not needed, StringBuilder might be an option.
By using a mutable CharSequence instead of the methods on String, you avoid a bunch of object churn. If all you're doing is replacing some slice of the underlying character array with a shorter array (i.e. {'*'}), this is likely to yield a speedup since such array copies are fairly optimized. You'll still be doing an array copy at the end of the day, but it may be faster than new String allocations.
UPDATE
All the above is pretty much hogwash. Sure, maybe you can implement your own CharSequence that gives you better slicing and lazily resizes the array (aka doesn't actually truncate anything until it absolutely must), returning Strings based on offsets and whatnot. But StringBuffer and StringBuilder, at least directly, do not perform as well as the solution poly posted. CharBuffer is entirely inapplicable; I didn't realize it was an nio class earlier: it's meant for other things entirely.
There are some interesting things about poly's code, which I wonder whether he/she knew before posting it, namely that changing the "*" on the final lines of the methods to a '*' results in a significant slowdown.
Nevertheless, here is my benchmark. I found one small optimization: declaring the '.' and "*" expressions as constants adds a bit of a speedup as well as using a locally-scoped StringBuilder instead of the binary infix string concatenation operator.
I know the gc() is at best advisory and at worst a no-op, but I figured adding it with a bit of sleep time might let the VM do some cleanup after creating 1M Strings. Someone may correct me if this is totally naïve.
Simple Benchmark
import java.util.ArrayList;
import java.util.Arrays;
public class StringSplitters {
private static final String PREFIX = "*";
private static final char DOT = '.';
public static String starOutFirst(String s) {
final int k = s.indexOf(DOT);
return PREFIX + s.substring(k);
}
public static String starOutFirstSb(String s) {
StringBuilder sb = new StringBuilder();
final int k = s.indexOf(DOT);
return sb.append(PREFIX).append(s.substring(k)).toString();
}
public static void main(String[] args) throws InterruptedException {
double[] firstRates = new double[10];
double[] firstSbRates = new double[10];
double firstAvg = 0;
double firstSbAvg = 0;
double firstMin = Double.POSITIVE_INFINITY;
double firstMax = Double.NEGATIVE_INFINITY;
double firstSbMin = Double.POSITIVE_INFINITY;
double firstSbMax = Double.NEGATIVE_INFINITY;
for (int i = 0; i < 10; i++) {
firstRates[i] = testFirst();
firstAvg += firstRates[i];
if (firstRates[i] < firstMin)
firstMin = firstRates[i];
if (firstRates[i] > firstMax)
firstMax = firstRates[i];
Thread.sleep(100);
System.gc();
Thread.sleep(100);
}
firstAvg /= 10.0d;
for (int i = 0; i < 10; i++) {
firstSbRates[i] = testFirstSb();
firstSbAvg += firstSbRates[i];
if (firstSbRates[i] < firstSbMin)
firstSbMin = firstSbRates[i];
if (firstSbRates[i] > firstSbMax)
firstSbMax = firstSbRates[i];
Thread.sleep(100);
System.gc();
Thread.sleep(100);
}
firstSbAvg /= 10.0d;
System.out.printf("First:\n\tMin:\t%07.3f\tMax:\t%07.3f\tAvg:\t%07.3f\n\tRates:\t%s\n\n", firstMin, firstMax,
firstAvg, Arrays.toString(firstRates));
System.out.printf("FirstSb:\n\tMin:\t%07.3f\tMax:\t%07.3f\tAvg:\t%07.3f\n\tRates:\t%s\n\n", firstSbMin,
firstSbMax, firstSbAvg, Arrays.toString(firstSbRates));
}
private static double testFirst() {
ArrayList<String> strings = new ArrayList<String>(1000000);
for (int i = 0; i < 1000000; i++) {
int first = (int) (Math.random() * 128);
int second = (int) (Math.random() * 128);
int third = (int) (Math.random() * 128);
int fourth = (int) (Math.random() * 128);
strings.add(String.format("%d.%d.%d.%d", first, second, third, fourth));
}
long before = System.currentTimeMillis();
for (String s : strings) {
starOutFirst(s);
}
long after = System.currentTimeMillis();
return 1000000000.0d / (after - before);
}
private static double testFirstSb() {
ArrayList<String> strings = new ArrayList<String>(1000000);
for (int i = 0; i < 1000000; i++) {
int first = (int) (Math.random() * 128);
int second = (int) (Math.random() * 128);
int third = (int) (Math.random() * 128);
int fourth = (int) (Math.random() * 128);
strings.add(String.format("%d.%d.%d.%d", first, second, third, fourth));
}
long before = System.currentTimeMillis();
for (String s : strings) {
starOutFirstSb(s);
}
long after = System.currentTimeMillis();
return 1000000000.0d / (after - before);
}
}
Output
First:
Min: 3802281.369 Max: 5434782.609 Avg: 5185796.131
Rates: [3802281.3688212926, 5181347.150259067, 5291005.291005291, 5376344.086021505, 5291005.291005291, 5235602.094240838, 5434782.608695652, 5405405.405405405, 5434782.608695652, 5405405.405405405]
FirstSb:
Min: 4587155.963 Max: 5747126.437 Avg: 5462087.511
Rates: [4587155.963302752, 5747126.436781609, 5617977.528089887, 5208333.333333333, 5681818.181818182, 5586592.17877095, 5586592.17877095, 5524861.878453039, 5524861.878453039, 5555555.555555556]