BIlling system - Programming - java

I require some input on the below logic.
It is kind of billing system takes the input and has a value associated with it.
A = 2 , 3A = 5
B = 3
C = 1 , 4C = 3
My code , should be such that take ABCCBAACCA , output should be value which is 16.
My solution as of now, I m thinking to count every element in the string, and them mod(modulus) by 3 for A , 4 for C (as in the above case, no need in case of B) every element in order to get the result.
I'm confused what data structure I should be using in order to implement such system.

In pseudocode I believe it would be:
Count all A's, B's and C's
Divide A's by 3 and multiply by 5
Modulo A's by 3 and multiply by 2
Multiply B's by 3
Divide C's by 4 and multiply by 3
Modulo C's by 4
Sum the 5 results.
In Ruby it could like something like this:
input = "ABCCBAACCA"
letters = ["A", "B", "C"]
total = 0
def score(letter,count)
if letter == "A"
((count/3)*5)+((count%3)*2)
elsif letter == "B"
count*3
else letter == "C"
((count/4)*3)+(count%4)
end
end
letters.each do |letter|
puts "#{letter}: #{score(letter, input.count(letter))}"
total += score(letter, input.count(letter))
end
puts "Total: #{total}"
Which produces:
A: 7
B: 6
C: 3
Total: 16

Well, the modulus operator won't help you since you will be getting 0 everytime is a multiple of 3 or 5, depending the letter you are evaluating (if thats what you trying to describe, sorry if i got it wrong).
I believe the easiest way is scanning the string and just adding the values.
When you encounter a third A you just add 1, instead of 2 (because you have to subtract 4, then add 5)
Similarly with C, you just add 0, instead of 1, when you encounter the fourth C.
You need 2 additional variables to keep the instances of A and C, and yes, you can use modulus operator to know if you just arrived to a multiple where you have to add either 1 or 0, depending the case.
Hope this helps a bit.
EDIT:
Here, I did a quick implementation. Feel free to optimize it if you really need it ;)
String value = "ABCCBAACCA";
int numA =0;
int numC =0;
int endResult = 0;
for (int x = 0; x < value.length(); x++)
{
if (value.charAt(x) =='A')
{
numA = numA +1;
endResult = endResult + ((numA%3 == 0)?1:2);
}
else if (value.charAt(x) =='B')
{
endResult = endResult +3;
}
else if (value.charAt(x) =='C')
{
numC = numC +1;
endResult = endResult + ((numC%4 == 0)?0:1);
}
}
System.out.println(endResult); //16 as expected

class CharBucket
attr_accessor :count
def initialize(thresholds)
#thresholds = thresholds
#count = 0
end
def total
#thresholds.inject([0, #count]) do |sum_left, a|
sum = sum_left[0]
left = sum_left[1]
sum += (left / a[0]) * a[1]
left %= a[0]
[sum, left]
end[0]
end
end
a = CharBucket.new({3 => 5, 1 => 2})
b = CharBucket.new({1 => 3})
c = CharBucket.new({4 => 3, 1 => 1})
buckets = {'A' => a, 'B' => b, 'C' => c}
"ABCCBAACCA".each_char{|c| buckets[c].count += 1 }
total = buckets.values.inject(0){|sum, b| sum += b.total} # => 16

Well, I would start with something like this:
public static void main(String[] args) {
// FIXME
String inputString = null;
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (Character c : inputString.toCharArray()) {
map = countCharacters(map, c);
}
}
private static Map<Character, Integer> countCharacters(Map<Character, Integer> map,
Character charatcer) {
map.put(charatcer,
(map.get(charatcer) != null) ? map.get(charatcer) + 1 :
Integer.valueOf(1));
return map;
}
and then introduce #vlasits steps from second to 5th, as this code above is first step in his pseudocode. It counts all characters in your string by making map of "character" : "its Occurences", if there was no such a character before, it puts 1 to the map.

Related

Counting occurrences of an array element - Index out of bounds error but the index number and out of bounds length are the same number?

So I'm having some issues with code I'm writing for an assignment and it's kinda driving me crazy. It's my first semester and I've never done coding before, so I know I still have heaps to learn. Anyways, the issues:
I'm having two problems which could be related but I'm not 100% sure. I'm getting this error:
'Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 125 out of bounds for length 125.'
Which points to the following section of code (Commented on specific line):
public static String gradesDistn() {
String gradeDistn = "0";
//Sort the above letterGrade array
Arrays.sort(letterGrade);
//This loop counts each occurrence of an element in the letterGrade array.
for (int i = 0; i < letterGrade.length - 1; i++) {
int count = 0;
for(int j = i + 1; j < letterGrade.length; j++) {
if (letterGrade[i] == letterGrade[j])
count++;
System.out.println (gradeDistn = letterGrade[i] + ": " + count); //THIS IS THE ERROR LINE.
i += (count-1);
}
}
return gradeDistn;
I can post the full code if additional context is needed. Essentially I'm am trying to count the occurrences of each letter grade (A, B, C, D, E and F) which are stored in an array. Each occurrence is based off of another array which stores number marks and is randomly generated. So the results should look something like this:
A: 6
B: 10
C:20
D: 9
E: 3
F: 1
instead I'm getting (copied from console):
A: 1
A: 2
A: 3
A: 4
B: 5
B: 6
B: 7
B: 8
B: 9
B: 10
B: 11
C: 11
C: 11
D: 11
D: 11
F: 11
C: 20
D: 9
E: 3
F: 1
I've spent so long looking at these code and trying to make it work, I feel like I'm am blind to the potentially obvious issues with it. Any help on this 2 issues would be really appreciated!
Also of note: The assignment requires a bunch of super specific methods such as this so that can't be changed, addition classes can not be used etc.
For this answer, I'm going to put aside the question of ArrayIndexOutOfBoundsException and offer guidance on how to generate a frequency distribution.
You are going to want a set of counters. Each counter will represent a range of values. To start, you should decide what range each counter will represent. Too fine a resolution, and your frequency distribution will not be very useful. For example, if your data is 100 meter sprint times for high school boys, and each counter represents an interval of 1/10,000 of a second, unless your sample size is very large, your frequency distribution would have a lot of values of '1' and '0'. You might want to separate by 1/10 of a second, 1 second, or 2 seconds, depending on how much variation there is in the boys' times.
But, if your data is species of farm animals, it would be fine to have a separate counter for each possible value.
So, determine how many counters you will need. What is the range of possible values? How closely do you want to group them?
Next, you will want a means of linking a particular value to a particular counter. In some cases, a little math can be used. In other cases, an if ... else if ... chain or a switch block is useful.
For the first example, I want to analyze daily high temperatures. I decide to group by 10 degrees Fahrenheit. I could decide on 5 degrees, 7 degrees, or some other interval. It could even be irregular intervals. But, keeping it regular and going by 10 degrees makes the example easier to follow.
Having settled on grouping by 10 degrees, I next want to decide the maximum and minimum. I'll pick -19 as the coldest, and 119 as the hottest. But, I want to allow for occurrences outside of that range. So, to hold the count, I will want an array of 15 counters.
Next, I will want a means of "translating" a temperature measurement to an array index. I use the int variable k for that in the following code. To make it easier to follow, I broke the calculation into 4 lines and then used the result as a subscript:
public static int [] tempFreqDist (WeatherStats [] daily) {
int [] count = new int [15]; // java initializes to zeros
int k;
for (int dIdx = 0; dIdx < daily.length; ++ dIdx) {
k = daily [dIdx].getHighTemp();
k = Math.max (k,-20);
k = Math.min (k,120);
k = k/10 + 2;
count [k]++;
}
return count;
}
That's it! One loop, and no sorting.
We want to group temps of -20 and colder together, regardless of how far below -20. So, we use Math.max. Similarly, we group temps of 120 and hotter by using Math.min. Next, divide by our grouping factor, and adjust the result so the lowest has 0 for the subscript value.
So, the result is the elements of count correspond to the temperature ranges: 0 ➔ -20 and colder; 1 ➔ "teens" (10 to 19) below zero; 2 ➔ single digits below zero; 3 ➔ zero and single digits above; 4 ➔ teens above zero; 5 ➔ twenties, ..., 14 ➔ teens above 100; 14 ➔ 120 and above.
But, suppose the 'width' of categories was irregular? One possibility is that you could use a chain of if ... else:
int t = daily [dIdx].getHighTemp();
if (t <= -20) k = 0;
else if (t <= -13) k = 1;
else if (t <= 0) k = 2;
else if (t <= 15) k = 3;
else if (t <= 28) k = 4;
and so on.
Another example counts animals you might see on a farm.
You can do that with an if ... else if ... chain:
public int[] animalFD (String [] species) {
int [] count = new int [6];
// 0 ➔ cattle, 1 ➔ pig, 2 ➔ sheep,
// 3 ➔ goat, 4 ➔ duck, 5 ➔ horse
...
for (int m = 0; m < species.length; ++m) {
if (species[m].equals("cow") count[0]++;
else if (species[m].equals("pig") count [1]++;
else if ...
But, for something like this, I prefer switch to if ... else chain:
public static int [] animalFD (String [] species) {
int [] count = new int [6];
for (int m = 0; m < species.length; ++m) {
switch (letterGrade [m]) {
case "cow":
count[0]++;
break;
case "pig":
count [1]++;
break;
case "sheep":
count [2]++;
break;
case "goat":
count [3]++;
break;
...
Here is a "trick" you can use to easily convert a letter to an index. Recall that a char is essentially a integer primitive: You can do numeric calculations on it.
char letter;
int idx;
...
if (letter >= 'A' && letter <= 'Z') {
idx = letter - 'A'; // result is zero to 25
...
This takes advantage of the fact that the letters A to Z are consecutive in character set encoding. However, that isn't universal. EBCDIC, for example, has non-letter characters between I and J, and between R and S, IIRC.

More efficient solution: Project Euler #2: Even Fibonacci Numbers

Problem:
Each new term in the Fibonacci sequence is generated by adding the
previous two terms.
By starting with 1 and 2, the first 10 terms will
be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms.
My code: (which works fine)
public static void main(String[] agrs){
int prevFirst=0;
int prevSecond=1;
int bound=4_000_000;
int evenSum=0;
boolean exceed=false; //when fib numbers > bound
while(!exceed){
int newFib=prevFirst + prevSecond;
prevFirst = prevSecond;
prevSecond = newFib;
if(newFib > bound){
exceed=true;
break;
}
if(newFib % 2 == 0){
evenSum += newFib;
}
}
System.out.println(evenSum);
}
I'm looking for a more efficient algorithm to do this question. Any hints?
When taking the following rules into account:
even + even = even
even + odd = odd
odd + even = odd
odd + odd = even
The parity of the first Fibonacci numbers is:
o o e o o e o o e ...
Thus basically, you simply need to do steps of three. Which is:
(1,1,2)
(3,5,8)
(13,21,34)
Given (a,b,c) this is (b+c,b+2*c,2*b+3*c).
This means we only need to store the two last numbers, and calculate given (a,b), (a+2*b,2*a+3*b).
Thus (1,2) -> (5,8) -> (21,34) -> ... and always return the last one.
This will work faster than a "filter"-approach because that uses the if-statement which reduces pipelining.
The resulting code is:
int b = 1;
int c = 2, d;
long sum = 0;
while(c < 4000000) {
sum += c;
d = b+(c<<0x01);
c = d+b+c;
b = d;
}
System.out.println(sum);
Or the jdoodle (with benchmarking, takes 5 microseconds with cold start, and on average 50 nanoseconds, based on the average of 1M times). Of course the number of instructions in the loop is larger. But the loop is repeated one third of the times.
You can't improve it much more, any improvement that you'll do will be negligible as well as depended on the OS you're running on.
Example:
Running your code in a loop 1M times on my Mac too 73-75ms (ran it a few times).
Changing the condition:
if(newFib % 2 == 0){
to:
if((newFib & 1) == 0){
and running it again a few times I got 51-54ms.
If you'll run the same thing on a different OS you might (and
probably will) get different results.
even if we'll consider the above as an improvement, divide ~20ms in 1M and the "improvement" that you'll get for a single run is meaningless (~20 nanos).
assuming consecutive Fibonacci numbers
a, b,
c = a + b,
d = a + 2b,
e = 2a + 3b,
f = 3a + 5b,
g = 5a + 8b = a + 4(a + 2b) = a + 4d,
it would seem more efficient to use
ef0 = 0, ef1 = 2, efn = efn-2 + 4 efn-1
as I mentioned in my comment there is really no need to further improvement.
I did some measurements
looped 1000000 times the whole thing
measure time in [ms]
ms / 1000000 = ns
so single pass times [ns] are these:
[176 ns] - exploit that even numbers are every third
[179 ns] - &1 instead of %2
[169 ns] - &1 instead of %2 and eliminated if by -,^,&
[edit1] new code
[105 ns] - exploit that even numbers are every third + derived double iteration of fibonaci
[edit2] new code
[76 ns] - decreased operand count to lower overhead and heap trashing
the last one clearly wins on mine machine (although I would expect that the first one will be best)
all was tested on Win7 x64 AMD A8-5500 3.2GHz
App with no threads 32-bit compiler BDS2006 Trubo C++
1,2 are nicely mentioned in Answers here already so I comment just 3:
s+=a&(-((a^1)&1));
(a^1) negates lovest bit
((a^1)&1) is 1 for even and 0 for odd a
-((a^1)&1)) is -1 for even and 0 for odd a
-1 is 0xFFFFFFFF so anding number by it will not change it
0 is 0x00000000 so anding number by it will be 0
hence no need for if
also instead of xor (^) you can use negation (!) but that is much slower on mine machine
OK here is the code (do not read further if you want to code it your self):
//---------------------------------------------------------------------------
int euler002()
{
// Each new term in the Fibonacci sequence is generated by adding the previous two terms.
// By starting with 1 and 2, the first 10 terms will be: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
// By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
int a,a0=0,a1=1,s=0,N=4000000;
/*
//1. [176 ns]
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // even
for (;a<N;)
{
s+=a;
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // even
}
//2. [179 ns]
for (;;)
{
a=a0+a1; a0=a1; a1=a;
if (a>=N) break;
if ((a&1)==0) s+=a;
}
//3. [169 ns]
for (;;)
{
a=a0+a1; a0=a1; a1=a;
if (a>=N) break;
s+=a&(-((a^1)&1));
}
//4. [105 ns] // [edit1]
a0+=a1; a1+=a0; a=a1; // 2x
for (;a<N;)
{
s+=a; a0+=a1; a1+=a0; // 2x
a=a0+a1; a0=a1; a1=a; // 1x
}
*/
//5. [76 ns] //[ edit2]
a0+=a1; a1+=a0; // 2x
for (;a1<N;)
{
s+=a1; a0+=a1; a1+=a0; // 2x
a=a0; a0=a1; a1+=a; // 1x
}
return s;
}
//---------------------------------------------------------------------------
[edit1] faster code add
CommuSoft suggested to iterate more then 1 number per iteration of fibonaci to minimize operations.
nice idea but code in his comment does not give correct answers
I tweaked a little mine so here is the result:
[105 ns] - exploit that even numbers are every third + derived double iteration of fibonaci
this is almost twice the speedup of 1. from which it is derived
look for [edit1] in code or look for //4.
[edit2] even faster code add
- just reorder of some variable and operation use for more speed
- [76 ns] decreased operand count to lower overhead and heap trashing
if you check Fibonacci series, for even numbers 2 8 34 144 610 you can see that there is a fantastic relation between even numbers, for example:
34 = 4*8 + 2,
144 = 34*4 + 8,
610 = 144*4 + 34;
this means that next even in Fibonacci can be expressed like below
Even(n)=4*Even(n-1)+E(n-2);
in Java
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
for(int a0 = 0; a0 < t; a0++){
long n = in.nextLong();
long a=2;
long b=8;
long c=0;
long sum=10;
while(b<n)
{
sum +=c;
c=b*4+a;
a=b;
b=c;
}
System.out.println(sum);
}
}
F(n) be the nth Fibonnaci number i.e F(n)=F(n-1)+F(n-2)
Lets say that F(n) is even, then
F(n) = F(n-1) + F(n-2) = F(n-2) + F(n-3) + F(n-2)
F(n) = 2F(n-2) + F(n-3)
--This proves the point that every third term is even (if F(n-3) is even, then F(n) must be even too)
F(n) = 2[F(n-3) + F(n-4)] + F(n-3)
= 3F(n-3) + 2F(n-4)
= 3F(n-3) + 2F(n-5) + 2F(n-6)
From eq.1:
F(n-3) = 2F(n-5) + F(n-6)
2F(n-5) = F(n-3) - F(n-6)
F(n) = 3F(n-3) + [F(n-3) - F(n-6)] + 2F(n-6)
= 4F(n-3) + F(n-6)
If the sequence of even numbers consists of every third number (n, n-3, n-6, ...)
Even Fibonacci sequence:
E(k) = 4E(k-1) + E(k-2)
Fib Sequence F= {0,1,1,2,3,5,8.....}
Even Fib Sequence E={0,2,8,.....}
CODE:
public static long findEvenFibSum(long n){
long term1=0;
long term2=2;
long curr=0;
long sum=term1+term2;
while((curr=(4*term2+term1))<=n){
sum+=curr;
term1=term2;
term2=curr;
}
return sum;
}
The answer for project Euler problem 2 is(in Java):
int x = 0;
int y = 1;
int z = x + y;
int sumeven = 0;
while(z < 4000000){
x = y;
y = z;
z = x + y;
if(z % 2 == 0){
sumeven += z; /// OR sumeven = sumeven + z
}
}
System.out.printf("sum of the even-valued terms: %d \n", sumeven);
This is the easiest answer.

Generating Number Pairs and GCD in Java

Problem: Given A,B print the number of pairs (a,b) such that GCD(a,b)=1 and 1<=a<=A and 1<=b<=B.
Solution (Brute Force Approach)
In the below code, i have used brute force approach and it works fine. However the execution time is more 10 sec if A & B > 10^5
Alternative Solution
From my research i found out that finding prime factors of A & B will reduce the execution time considerably (< 3 sec), but i'm not sure how to apply it.
Need Help:
Can anyone help me to arrive at the result with < 3 sec execution time?
class GCD {
public static void main(String[] args) {
int A = 0, B = 0, GCD = 0, count = 0;
BigInteger B1, B2 = null;
A = Integer.parseInt(args[0]);
B = Integer.parseInt(args[1]);
for (int a = 1; a <= A; a++) {
for (int b = 1; b <= B; b++) {
B1 = BigInteger.valueOf(a);
B2 = BigInteger.valueOf(b);
GCD = calculateGCD(B1, B2);
if (GCD == 1) {
count++;
}
}
}
System.out.println(count);
}
public static int calculateGCD(BigInteger number1, BigInteger number2) {
return (number1.gcd(number2)).intValue();
}
}
I do not want to write a complete programm or something, but I want to give you some tips for speeding up your program:
gcd(a,b) = gcd(b,a) so only compute pairs (a, b) with a < b. gcd(a,a) = 1 holds only for a = 1. Also gcd(1,b) = 1 for all b, so you can start with a = 2 and a count = 1 + 2*(B-1).
compute all primefactors for all 1 < a <= A at once by using something like the Sieve of Eratosthenes. E.g. every secound number contains primefactor 2, every third the primfactor 3.
You do not need to compute the gcd. Let a contain the distinct primfactors p and q. Then you know:
There are B-a numbers to test.
Every p-th number contains also the primfactor p, every q-th primenumber also contains the primfactor q. floor( (B-a)/p ) numbers have a gcd >= p and floor( (B-a)/q ) numbers have a gcd >= q and floor( (B-a)/(p*q) ) numbers have you counted twice. So you can get the number of pairs (a,b) with a < b as
(B-a) - floor( (B-a)/p ) - floor( (B-a)/q ) + floor( (B-a)/(p*q) )
if you want also the pairs it self, you can use a for-loop and jump every step where i (for-loop counter) is divisable by any primefactor of a
I think this should speed up your program as much as you need to reach less than a second.

How to "invert" numbers in Java

Lets say I have a number 1-5, now if I have 2, I want 4 as an output, if I had 3 then have 3 as the output, if I have 1 then 4 as the output. Here is a chart of what I want:
1-10 Chart:
Give 1 return 9
Give 2 return 8
Give 3 return 7
Give 4 return 6
Give 5 return 5
What algorithm do I use for such a thing?
I don't see that you need an algorithm as much. What you have is:
InverseNumber = (myCollection.Length - MySelection);
Thats all you need for even numbers.
With a collection of 1 - 6 for example:
Give 2; 6 - 2 = 4. Also if given 4, 6 - 4 = 2.
You will need a slightly different problem for odds:
1 - 5; with 1 given 1 is at index 0, the opposite is 5, 2 given and the inverse ( 5 - 2) is 3. But if 3 is given, there is no inverse. So you might want to also add a catch for:
if (((myCollection.Length *.5).Round) == mySelection) { //Inverse does not exist!!!}
If you are using just integers, and not arrays of numbers then just replace the myCollection.Length with the upperbound integer.
I think the following code will work for what you need:
int a[] = new a[length_needed];
int counter = length_needed;
for(int c = 0; c < length_needed; c++) {
a[c] = counter;
counter--;
}
int number_inputed;
for(int c = 0; c < length needed; c++) {
if(c == number_inputed) System.out.println(a[c]);
}
Let's say you are giving max number as input. Then you are going to have 0-n numbers. For ex., if 9 is the max number you will have 0-9.
Then you can do something like this:
public static void main(String[] a) {
int max = a[0]; // read values from cmd line args
int forWhichNum = a[1]; //for which number we need its inverse
Sop(max- forWhichNum);
}
Integer value = 2;
Integer maxValue = 6;
Integer reverseCounter = 0;
for (int i = maxValue; i > 0; i--) {
reverseCounter++;
if (i == value) {
return reverseCounter;
}
}

How Can I Convert Very Large Decimal Numbers to Binary In Java

For instance, How would I be able to convert 2^60 or 12345678901234567890123456789012345678901234567890 to binary?
Basically, numbers that are too large to represent in Java.
Edit: I will be making a class that will be able to represent number that are too large. I'm just having a hard time figuring our how to convert decimal to binary.
Edit2: And also, I am not allowed to use BigDecimal, BigInteger, or any other library, sorry for not specifying earlier.
Here is a quik&dirty (very very very dirty) code:
public class BigDec2Bin {
public static int[] string2arrayReversed( String s )
{
char a[] = s.toCharArray();
int b[] = new int[ s.length() ];
for( int i = 0; i < a.length; i++ )
{
b[a.length-1-i] = a[i] - 48;
}
return b;
}
// adds two binary numbers represented as strings
public static String add( String s1, String s2 )
{
String result = "", stmp;
int[] a1, a2;
int ctmp, mark = 0;
// a1 should be the longer one
a1 = string2arrayReversed( ( s1.length() > s2.length() ? s1 : s2 ) );
a2 = string2arrayReversed( ( s1.length() < s2.length() ? s1 : s2 ) );
for( int i = 0; i < a1.length; i++ )
{
ctmp = a1[i] + ( i < a2.length ? a2[i] : 0 ) + mark;
switch( ctmp )
{
default:
case 0:
stmp = "0";
mark = 0;
break;
case 1:
stmp = "1";
mark = 0;
break;
case 2:
stmp = "0";
mark = 1;
break;
case 3:
stmp = "1";
mark = 1;
break;
}
result = stmp + result;
}
if( mark > 0 ) { result = "1" + result; }
return result;
}
public static String dec2bin( String s )
{
String result = "";
for( int i = 0; i < s.length() ; i++ )
{
result = add( result + "0", result + "000" );
result = add( result, Integer.toBinaryString( s.charAt(i) - 48 ) );
}
return result;
}
public static void main( String[] args )
{
String dec = "12345"; // should be 11000000111001
System.out.println( "dec2bin( " + dec + " ) = " + dec2bin( dec ) );
dec = "12345678901234567890123456789012345678901234567890";
System.out.println( "dec2bin( " + dec + " ) = " + dec2bin( dec ) );
}
}
Output:
dec2bin( 12345 ) = 011000000111001
dec2bin(
12345678901234567890123456789012345678901234567890
) =
10000111001001111111011000110110100110101010111110000011110010100001010100000010011001110100011110101111100011000111111100011001011011001110001111110000101011010010
My main idea is to use always strings.
add -method adds two binary numbers which are represented as strings
dec2bin -method is where the magic happens.
Allow me to explain:
result = add( result + "0", result + "000" );
is a calculation to multiply any given number by 10.
Multiplying a binary number by 10 is the same as adding the number with shifts:
x*10 <=> x<<1 + x<<3
result = add( result, Integer.toBinaryString( s.charAt(i) - 48 ) );
just adds a the next digit (from left to right) on the result string
Basicly what I'm doing is for example with 1234:
0*10 + 1 = 1
1*10 + 2 = 12
12*10 + 3 = 123
123*10 + 4 = 1234
but only in binary (represented as strings).
I hope i could help and sorry for my bad english.
Try this:
new BigDecimal("12345678901234567890123456789012345678901234567890").toString(2);
Edit:
For making a big-number class, you may want to have a look at my post about this a week ago. Ah, the question was by you, never mind.
The conversion between different number systems in principle is a repeated "division, remainder, multiply, add" operation. Let's look at an example:
We want to convert 123 from decimal to a base 3 number. What do we do?
Take the remainder modulo 3 - prepend this digit to the result.
Divide by 3.
If the number is bigger than 0, continue with this number at step 1
So it looks like this:
123 % 3 == 0. ==> The last digit is 0.
123 / 3 == 41.
41 % 3 == 2 ==> The second last digit is 2.
41 / 3 == 13
13 % 3 == 1 ==> The third digit is 1.
13 / 3 == 4
4 % 3 == 1 ==> The fourth digit is 1 again.
4 / 3 == 1
1 % 3 == 1 ==> The fifth digit is 1.
So, we have 11120 as the result.
The problem is that for this you need to have already some kind of division by 3 in decimal format, which is usually not the case if you don't implement your number in a decimal-based format (like I did in the answer to your last question linked above).
But it works for converting from your internal number format to any external format.
So, let's look at how we would do the inverse calculation, from 11120 (base 3) to its decimal equivalent. (Base 3 is here the placeholder for an arbitrary radix, Base 10 the placeholder for your internal radix.) In principle, this number can be written as this:
1 * 3^4 + 1 * 3^3 + 1*3^2 + 2*3^1 + 0*3^0
A better way (faster to calculate) is this:
((((1 * 3) + 1 )*3 + 1 )*3 + 2)*3 + 0
1
3
4
12
13
39
41
123
123
(This is known as Horner scheme, normally used for calculating values of polynomials.)
You can implement this in the number scheme you are implementing, if you know how to represent the input radix (and the digits) in your target system.
(I just added such a calculation to my DecimalBigInt class, but you may want to do the calculations directly in your internal data structure instead of creating a new object (or even two) of your BigNumber class for every decimal digit to be input.)
What about this approach:
result = 0;
for each digit in the decimal number, from left to right
result = result * 10 + digit;
return result;
So we need a way to represent an arbitrarily large binary number, and implement multiplication by 10 and addition of small numbers.
The most straightforward way to represent an arbitrarily large binary number is an array of its binary digits. You can then apply the algorithms for addition and multiplication your learned in elementary school, except that digits will "overflow" when they exceed 1 rather than 9. For example:
1010 * 1100111
----------------
11001110
+ 1100111000
----------------
10000000110
Pew: thanks, that works for some numbers. The number 6123456789012 however doesn't work, but here is the fix:
// a1 should be the longer one
a1 = string2arrayReversed( ( s1.length() >= s2.length() ? s1 : s2 ) ); //GREATER EQUAL
If you only work with integers, use BigInteger.toByteArray.
If not, unfortunately BigDecimal doesn't have that method. But I suppose you can always (in both cases) just ASCII encode the string representation of the number, if the binary form is just meant for transfer and not calculation anywhere.
there is a fast program to get the binary representation of a huge decimal.
This programm is indeed fast, it takes only 20ms to deal with a decimal with 3000digits, eg:string(3000,'2')+'12345'. because of the pursuit of efficiency, it is not very readable. you can modify it yourself to make it easier to understand.
inline string remove_pre_zero(const string& a)
{
auto t = a.find_first_not_of('\0', 0);
if (t == a.npos)
return string("0");
else
return a.substr(t);
}
string convert_to_bin(const string& _s)
{
const static string str[] = { "0", "1" };
string s(_s.size(), '0');
string binary;
binary.reserve(_s.size()*3);
int i = 0;
for (const auto& c : _s)
s[i++] = (c - '0');
while (s!="0")//simulate divide by 2
{
int t = 0, old_t = 0;
for (auto& ch : s)
{
t = ((old_t * 10 + ch) & 1);
ch = (ch + old_t * 10) >>1;
old_t = t;
}
binary += str[t];
if (s[0] == 0)
s = remove_pre_zero(s);
}
return string(binary.rbegin(), binary.rend());
}

Categories

Resources