-1

I have this function:

 private double getTotal(string str)
    {
        double total = 0;
        byte[] asciiBytes = Encoding.ASCII.GetBytes(str);

        foreach(int c in asciiBytes)
        {
            total = total + c;
            total = total * (5 * (c ^ 2) / (c*6));
        }
        return Math.Round(total);
    }

This is used to get a total of a strings ASCII values but does some math along the way rather than just adding. I need this to return the total, but is currently returning 0. How can I make it return the correct value? (PS: It needs to return an integer, but this can be in the datatype of a double for conversion later. Basically just need it to return a whole number.) (PSPS: I don't know what the string will be, it's up to the end user)

_

Leo Skingsley
  • 43
  • 1
  • 6
  • 4
    What do you think `c ^ 2` does? (If you expect that to be XOR, you're correct) – Ben Voigt May 17 '17 at 18:57
  • 2
    `Math.Pow(c, 2)` may be what Ben is gently hinting at, or maybe I should say guessing at. – 15ee8f99-57ff-4f92-890c-b56153 May 17 '17 at 18:57
  • What _is_ "the correct value"? Hint: multiplying a value by 0 yields 0. It's not clear what math operation you actually wanted here. And without a clear specification explaining what outcome you expected, there's no useful way to know what your goal is. You can probably solve this yourself by stepping through the code with a debugger, evaluating expressions as you go along, until you find a calculation that comes out differently than you expected. – Peter Duniho May 17 '17 at 18:57
  • @EdPlunkett: Well, I honestly don't know whether that code is trying to do XOR or squaring. – Ben Voigt May 17 '17 at 18:58
  • Nope. I though it was for exponentiation – Leo Skingsley May 17 '17 at 18:58
  • @BenVoigt True, but who xors a double? – 15ee8f99-57ff-4f92-890c-b56153 May 17 '17 at 18:58
  • 1
    If its squaring, the equation can be simplified. c^2/c = c. The whole equation can boil down to `total*(5/6)*c` –  May 17 '17 at 18:58
  • 2
    Since `c ^ 2` is roughly the same magnitude as `c`, it's likely that `5 * (c^2)` is smaller than `6 * c`, and then the integer division results in zero. – Ben Voigt May 17 '17 at 18:58
  • Now it's returning some huge number, I think the fact that `^` is XOR was one of the problems, though. – Leo Skingsley May 17 '17 at 19:00
  • 1
    @EdPlunkett: This appears to be some type of hashing function, XOR is not uncommon in hashing. – Ben Voigt May 17 '17 at 19:00
  • @BenVoigt Ohhhhhhhhh, derp. – 15ee8f99-57ff-4f92-890c-b56153 May 17 '17 at 19:01
  • Yes it's for hashing, I won't be using that exact equation for obvious reasons. Well I will but I'll substitute new, bigger numbers – Leo Skingsley May 17 '17 at 19:02
  • Explain to us or think about what the second statement in the foreach loop is doing/should be doing. – Ravi Yenugu May 17 '17 at 19:03
  • @amy, 5/6 is zero... – Alexei Levenkov May 17 '17 at 19:03
  • The truth is I'm basing this off an old python script, I was mainly just running a few math ops on the number to make it slightly larger, as it will be used for encryption. `total = total + c;` was just an initial test. – Leo Skingsley May 17 '17 at 19:04
  • @AlexeiLevenkov It's about 0.83 – Leo Skingsley May 17 '17 at 19:05
  • 1
    @AlexeiLevenkov okay? Then change it to 5.0/6. My point remains - the equation can be simplified. –  May 17 '17 at 19:07
  • I think I see the issue, total starts as 0, `0 * x` will always equal 0. – Leo Skingsley May 17 '17 at 19:12
  • I rather like use of XOR there, because the fraction comes out near one, so it doesn't cause the magnitude of the value to explode, and keeps the contribution of each letter of the string more-or-less equal. You do have to avoid the integer division though. – Ben Voigt May 17 '17 at 19:13
  • @LeoSkingsley: It's not zero after `total = total + c;` It's the thing you're multiplying by that is zero, due to integer division. – Ben Voigt May 17 '17 at 19:13
  • It indeed was, changing total to something more than 1 at the start fixes it. Derp. – Leo Skingsley May 17 '17 at 19:13
  • No I removed that statement – Leo Skingsley May 17 '17 at 19:13
  • @Amy indeed I expect you to know how to write it properly... OP on other hand claimed that 5/6=0.83 which demonstrates potential misunderstanding of how math operations differ in [ℝ](https://en.wikipedia.org/wiki/Real_number) vs. [ℤ](https://en.wikipedia.org/wiki/Integer) (double/float/decimal vs. byte/int/long/BigInteger) are implemented by languages with roots in C... – Alexei Levenkov May 17 '17 at 19:49
  • @AlexeiLevenkov I was writing a math equation, not code. I wrote it exactly how I meant to, following the word "equation". If you read my comment as code, I'm sorry? –  May 17 '17 at 19:55
  • "I don't know what the string will be, it's up to the end user": You do realize that your algorithm will only work if all the characters the user passes in `str` are in the [C0 Controls and Basic Latin](http://www.unicode.org/charts/nameslist/index.html) Unicode block. You could guard it by using `Encoding.GetEncoding("US-ASCII", EncoderExceptionFallback.ExceptionFallback, DecoderExceptionFallback.ExceptionFallback)` instead of `Encoding.ASCII`. Test with "". That'll tell the user which character was unexpected (but only tell a developer which characters are acceptable). – Tom Blodget May 17 '17 at 22:23

4 Answers4

1

You probably misunderstood the ^ sign. It stands for a bitwise exclusive or, rather than an exponentiation. If you want to use the latter, use this:

total = total * (5 * (Math.Pow (c, 2) / (c * 6));

However, you could write it shorter/more beautiful/more efficient as well:

total *= (5 * (c * c) / (6 * c));

I replaced the Pow, as it is slower than a simple multiplication and used an assignment-operator.

Furthermore, the equation itself can be simplified:

total *= c * (5 / 6);

However, you should still mark the numbers as doubles, as 5/6 would result in 0 otherwise:

total *= c * (5.0 / 6.0)

For more information on exponentiation in C#, have a look at this.


By the way, the ^ sign takes every bit of the numbers and compares them. The new value will be 1 if the first bit or the second bit, but not both bits are 1.

So for example 0101 xor 1110 would result in 1011.

Community
  • 1
  • 1
MetaColon
  • 2,895
  • 3
  • 16
  • 38
0

You have casting problem. The c variable is integer. Your problem is in the total = total * (5 * (c ^ 2) / (c*6)); expression.

Because the internal results (c ^ 2) and (c*6) aren't double, when the division result has floating point such as 0.nnnnn, the final result isn't double and you get only the 0 which is the real part of the number. And the result expression (5 * (c ^ 2) / (c*6)) as an Integer is 0. Finally the expression is as total=total * (0);

Use internal castings in your code Replace your code with the following :

total = total * (5 * ((double)(c ^ 2)) / ((double)(c * 6)));

Please run the following code

    static private double getTotal(string str)
    {
        double total = 0;
        byte[] asciiBytes = Encoding.ASCII.GetBytes(str);

        foreach (int c in asciiBytes)
        {
            double dC = c;
            total = total + c;
            double cXor2 = c ^ 2;
            double c6 = c * 6;
            double fiveCXor2 = 5 * cXor2;
            double semiFinal = fiveCXor2 / c6;
            double final = total * semiFinal;

            Console.WriteLine("c = " + (c).ToString());
            Console.WriteLine("c ^ 2 = " + (cXor2).ToString());
            Console.WriteLine("c * 6 = " + (c6).ToString());
            Console.WriteLine("5 * (c ^ 2) = " + (fiveCXor2).ToString());
            Console.WriteLine("semi final = " + semiFinal);
            Console.WriteLine("final = " + final);
            Console.WriteLine("--------------------------------------------");
            total = total * (5 * (c ^ 2) / (c * 6));
            Console.WriteLine("TOTAL = " + total);
            Console.WriteLine("--------------------------------------------");
        }
        return Math.Round(total);
    }

Sample result is :

c = 97
c ^ 2 = 99
c * 6 = 582
5 * (c ^ 2) = 495
semi final = 0.850515463917526
final = 82.5
--------------------------------------------
TOTAL = 0
--------------------------------------------
c = 98
c ^ 2 = 96
c * 6 = 588
5 * (c ^ 2) = 480
semi final = 0.816326530612245
final = 80
--------------------------------------------
TOTAL = 0
--------------------------------------------

As you can see the problem is casting

Because the c variable is int the casting procedure is :

step 1
[double] = [double] * ([int] * ([int] ^ [int] ) / ([int] * [int] )) 
total    = total    * (5     * (c     ^ 2     ) / (c     * 6     ));

step 2
[double] = [double] * ([int] * ([int]) / ([int] )) 
total    = total    * (5     * (X)     / (Y)    );

step 3
[double] = [double] * ([int] * [int])) 
total    = total    * (5     * XdivY    );
**CASTING PROBLEM : In this step the XdivY is integer and when the result is 0.1234 the INT     result is 0**

step 4
[double] = [double] * ([double])) 
total    = total    * (5mulXdivY    );    
here c# casting the 5mulXdivY  0  to double but the result is zero

step 5
[double] = [double] 
total    = 0
  • Are you sure about the real part? I thought this just matters with complex numbers. – MetaColon May 17 '17 at 19:34
  • I added some additional info –  May 17 '17 at 19:55
  • However, I still don't think it's called *real part*, but *integer-part*. (See for example here: https://math.stackexchange.com/questions/64042/what-are-the-numbers-before-and-after-the-decimal-point-referred-to-in-mathemati) – MetaColon May 17 '17 at 20:09
  • @MetaColon my English is poor and its my mistake. Sorry. –  May 18 '17 at 07:02
0

Problem is with the this line in your code

total = total * (5 * (c ^ 2) / (c*6));

c ^ 2 returns a smaller value than c*6. Now the operator / is integer division so the result of a smallnumber/largenumber will always return zero. This will make the value of variable total zero in every iteration of the loop. Change the code like this and it will give you the result you expect.

private double getTotal(string str)
        {
            double total = 0;
            byte[] asciiBytes = Encoding.ASCII.GetBytes(str);

            foreach (int c in asciiBytes)
            {
                total = total + c;
                total = total * (5 * (double)(c ^ 2) / (double)(c * 6));
            }
            return Math.Round(total);
        }

Hope it helps.

-2

Add double to one of the ints

private double getTotal(string str)
        {
            double total = 0;
            byte[] asciiBytes = Encoding.ASCII.GetBytes(str);

            foreach (int c in asciiBytes)
            {
                total = total + c;
                total = total * ((double)5 * (c ^ 2) / (c * 6));
            }
            return Math.Round(total);
        }
Artyom
  • 1,065
  • 8
  • 12
  • Why down vote? This is actually working. "(5 * (c ^ 2) / (c*6))" this expression operate "int" so when you C ^ 2 or any other operation inside this expression it is actually int and automatically truncated to int. you need to add double boxing to change it. – Artyom May 17 '17 at 19:04
  • 2
    I didn't downvote, but `(double)5` is a rather silly way of writing `5.0` – Ben Voigt May 17 '17 at 19:07
  • It is not important here, point is that it was int and if it was only, for example, "c" in expression (double) would make it understandable, but 5.0 is a particular case. – Artyom May 17 '17 at 19:10
  • `5.0` is much more readable than `(double)5`. `5d` is also easier to read. You should change the `^` to `Math.Pow`, as discussed in the comments on the question. –  May 17 '17 at 19:12
  • Yes if it 5, but in case it would be "total = total * (c * (c ^ c) / (c * c));", more general answer here is a (double). That i was trying to explain :) – Artyom May 17 '17 at 19:13
  • 1
    @Amy: The fact that it immediately simplifies if you treat `^` as exponentiation suggests that maybe it really should be left as XOR. – Ben Voigt May 17 '17 at 19:15