Are bitwise operator working on __int128 in c++ - c++

I'm working on a project where I have to transform a __int128 into a vector of uint8_t.
I have already a function that transform a long into a vector of uint8_t.
I wanted to do something like :
__int128 data = 0x5bc5ddd975d34ed0b4f18b410e7d2480
addLong(data >> 64);
addLong(data & 0xFFFFFFFFFFFFFFFF);
and I'm getting this as a result : 00000000b4f18b41e7d2480
As you can see, the second part, the 64 less significant bytes are correctly treated, but the most ones aren't.
Do you know if this is possible ?
Doing something like that :
std::cout << std::hex << (long)(data >> 48) << std::endl;
gives me the result : b4f1.
That's why I think bitwise operator aren't working with __int128.

gcc unfortunately still doesn't support __int128 / unsigned __int128 literals (there's no suffix for them like ll for long long).
Your example should produce a warning that your literal value gets truncated to a long long value:
godbolt
warning: integer constant is too large for its type
| __int128 data = 0x5bc5ddd975d34ed0b4f18b410e7d2480;
|
(if you don't get one then you've most likely disabled -Wconversion - it's enabled by default)
The bitwise operations should work without problems.
In case you want to utilize the standard library functions (std::abs, etc...) for 128-bit ints you need to make sure that you're not compiling in a strict standard mode (i.e. -std=c++20), but rather in a gnu dialect of the standard (i.e. -std=gnu++20) (this is the default if you don't specify -std at all) - otherwise the int128 overloads for std::abs, etc... won't be available.
User-defined literals
Utilizing C++20 consteval and user-defined literals its possible to build a custom compile-time literal for __int128.
(it would be possible to use this pre-C++20 by substituting consteval with constexpr, but in that case you wouldn't get compile-time errors if something is wrong with the literal)
It is a lot of boilerplate for int parsing though, but it might be worth it in case you have a lot of __int128 literals within your program:
godbolt
#include <stdexcept>
#include <cctype>
#include <bit>
namespace int128_literal {
// determines the base of the given digit string
// and increments str past it
consteval int determine_base(const char*& str) {
int base = 10;
if(str[0] == '0') {
if(str[1] == 'x' || str[1] == 'X') {
// hexadecimal
str += 2;
base = 16;
} else if(str[1] == 'b' || str[1] == 'B') {
// binary
str += 2;
base = 2;
} else if(
str[1] == '0' || str[1] == '1' || str[1] == '2' ||
str[1] == '3' || str[1] == '4' || str[1] == '5' ||
str[1] == '6' || str[1] == '7'
) {
// octal
str += 1;
base = 8;
} else if(str[1] == '\0') {
// zero literal
base = 8;
} else {
throw std::logic_error("unknown literal prefix!");
}
}
return base;
}
// parses the given hexadecimal digit.
// returns -1 for the digit separator (')
consteval int parse_digit(char character) {
switch(character) {
case '\'':
// digit separator
return -1;
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default:
throw std::logic_error("Unknown digit in literal!");
}
}
consteval unsigned __int128 parse(const char* str) {
// nullptr
if(!str)
throw std::logic_error("nullptr!");
bool is_negative = false;
if(*str == '-') {
str++;
is_negative = true;
}
// determine base
int base = determine_base(str);
int parsed_digits = 0;
unsigned __int128 value = 0;
while(*str != '\0') {
int digit = parse_digit(*str);
// digit separator
if(digit == -1) {
if(parsed_digits == 0)
throw std::logic_error("digit separator not allowed at beginning of literal!");
else if(*(str + 1) == '\0')
throw std::logic_error("digit separator not allowed at end of literal!");
str++;
continue;
}
// check if digit is allowed in current base
switch(base) {
case 2:
if(digit > 1)
throw std::logic_error("only 0-1 allowed for binary!");
break;
case 8:
if(digit > 7)
throw std::logic_error("only 0-7 allowed for octal!");
break;
case 10:
if(digit > 9)
throw std::logic_error("only 0-9 allowed for decimal!");
break;
}
unsigned __int128 next_value = value * base;
// detect overflow during multiply
if(next_value / base != value)
throw std::logic_error("literal too large for unsigned __int128!");
next_value += digit;
// detect overflow during addition
if(next_value < value) {
throw std::logic_error("literal too large for unsigned __int128!");
}
value = next_value;
str++;
parsed_digits++;
}
if(parsed_digits == 0) {
throw std::logic_error("no digits in literal!");
}
// negate two's complement
if(is_negative) {
value = ~value + 1;
}
return value;
}
consteval unsigned __int128 operator""_uint128(const char* str)
{
return parse(str);
}
consteval unsigned __int128 operator""_uint128(const char* str, std::size_t)
{
return operator""_uint128(str);
}
consteval __int128 operator""_int128(const char* str)
{
unsigned __int128 value = parse(str);
return std::bit_cast<__int128>(value);
}
consteval __int128 operator""_int128(const char* str, std::size_t)
{
return operator""_int128(str);
}
}
using int128_literal::operator""_int128;
using int128_literal::operator""_uint128;
This would then allow you to write __int128 / unsigned __int128 literals like this:
godbolt
// numeric literal:
__int128 a = 0x5bc5ddd975d34ed0b4f18b410e7d2480_int128;
unsigned __int128 b = 340'282'366'920'938'463'463'374'607'431'768'211'455_uint128;
__int128 c = -0b11111111111111010101010101010101001010101010010101001_int128;
__int128 d = 075642412376_int128;
// or as string literal:
__int128 a = "0x5bc5ddd975d34ed0b4f18b410e7d2480"_int128;
unsigned __int128 b = "340'282'366'920'938'463'463'374'607'431'768'211'455"_uint128;

The bitwise operators work, but your initialization does not. The integer literal can't be bigger than a long long.
I suggest adding a helper function for the initialization (if there isn't already one in gcc):
#include <cstdint>
#include <iostream>
__int128 init_int128(std::int64_t high, std::uint64_t low) {
return __int128(high) << 64 | low;
}
int main() {
__int128 data = init_int128(0x5bc5ddd975d34ed0, 0xb4f18b410e7d2480);
std::cout << std::hex;
std::cout << static_cast<std::int64_t>(data >> 64) << '\n';
std::cout << static_cast<std::uint64_t>(data) << '\n';
}
Output
5bc5ddd975d34ed0
b4f18b410e7d2480

Related

Inputting 30-something and -Ex42 with an output of 30 and Ex42

I can't understand how I would do this.
The input will be:
3
13894
30-something
-Ex42
and the output needs to be:
13894
30
Ex42
The main assignment is to make a function that converts a duodecimal number into the decimal format. I have figured that part out and don't need help with it. I've basically cut out all the code surrounding the duodecimal conversion and just included the stuff I can't figure out.
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int to_decimal(const string& str);
int main () {
string str; // Initializes string str for input
cin.ignore (256, '\n'); //ignores the 3 from the input
while (getline(cin, str)) {
//runs str through to_decimal and outputs
cout << to_decimal(str) << endl;
}
}
int to_decimal(const string& str) {
int f = 0;
string localString; // Initialize local string variable
//sets local string to the same as inputted string
localString = str; //used for local string erasing
//This is the idea I have been working on and I cant figure it out
for (unsigned x = 0; x < localString.length(); x++) {
f = localString.at(x);
if (isdigit(f)) {
} else if (f == 'E'){
} else if (f == 'e') {
} else if (f == 'X') {
} else if (f == 'x') {
} else if (f == '-') {
} else if (f == ' ') {
} else {
f = localString.length() - x;
localString.erase(x, f);
break;
}
}
}
I am a bit confused. You say that you need to convert duodecimal numbers to decimal, however in your sample output only the line that has Ex is converted, yet 30-something stays 30, as if it is not converted - and 30 in duodecimal is 36 in decimal. Same for the number 13894.
Assuming that you really want to convert all of the lines from duodecimal to decimal, you can base your solution on the standard library function std::stoi() which can convert a string from most number bases up to 36. It requires that the digits bigger than 9 are encoded using the letters in alphabetic order - A to Z. So you need to simply convert all you x to a and all you e to b. Example:
int to_decimal(const string& str) {
bool foundDigit = false;
std::string transformedString;
for (auto c : str) {
if (std::isdigit(c) || c == 'E' || c =='e' || c == 'X' || c == 'x') {
foundDigit = true;
// If needed, convert the character.
if (c == 'E' || c == 'e') {
c = 'b';
} else if (c == 'X' || c == 'x') {
c = 'a';
}
transformedString += c;
} else if (foundDigit) {
// Skip everything to the end of the line, if we've already found some digits
break;
}
}
return std::stoi(transformedString, 0, 12);
}
If you just want to extract the characters and then do the conversion yourself, then you can do something like this:
#include <iostream>
#include <string>
#include <sstream>
bool isNumber(const char c)
{
switch (c) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
case 'e':
case 'E':
case 'x':
case 'X':
case '-':
return true;
default:
return false;
}
}
std::string getNumber(std::istream& in)
{
std::stringstream s;
for (char c;in.get(c);)
{
if (isNumber(c)) {
s << c;
break;
}
}
for (char c;in.get(c);)
{
if (!isNumber(c))
break;
s << c;
}
return s.str();
}
int main()
{
std::string bla = "3\n13894\n 30-something\n-Ex42\n";
std::stringstream klaf{ bla };
for (std::string s;(s = getNumber(klaf)) != "";) //<- use a local stringstream as input to test
//for (std::string s;(s = getNumber(std::cin)) != "";) //<- use std::cin for input
{
std::cout << s << '\n';
}
}
This outputs:
3
13894
30-
e
-Ex42
So, not exactly what you were after, but it should at least get you a starting point to improve from. For example, you may want to remove - from isNumber and then change to logic in getNumber to only accept it as the first character in a new number.

Failing to parse different math operators

This question is a follow-up from this one. Basically I'm trying to make a parser which calculates the total result of a string. 5+5+3*2/1 should give 16. This already works for strings only containing plusses and mins, so -55-44+1-2+123-54442+327737+1-2 successfully gives 273317.
It however does not work when plusses/mins get mixed with times/divides. So 1*2-2*3 returns 6 instead of -4. I think this is because I try to respect the order in which math needs to be executed (first plusses and mins, than times and division), but the operator somehow doesn't get updated.
#include <iostream>
#include <string>
#include <algorithm>
//Enumeration of all the possible
//math operators
enum Operator {
PLUS,
MIN,
TIMES,
DIVIDE,
UNDEFINED
};
/************************IGNORE********************/
char operatorToChar(Operator o) {
switch(o) {
case Operator::PLUS:
return '+';
break;
case Operator::MIN:
return '-';
break;
case Operator::TIMES:
return '*';
break;
case Operator::DIVIDE:
return '/';
break;
default:
return '0';
break;
}
}
/***************************************************/
/*
* Function to check if there are still times- or divide-operators in the action string.
* This to respect the order of math (first times and divides, than plusses and mins)
*
* :param action: The action string
* :return bool: Returns true if a '*' or '/' is found
*/
bool timesAndDividesGone(std::string& action) {
for (char& c : action) {
if (c == '*' || c == '/') {
return false;
}
}
return true;
}
/*
* Function to convert char to Operator
* :param c: One of the following '+', '-', '*', '/'
* :return Operator: Operating matching the character
*/
Operator charToOperator(char c) {
switch(c) {
case '+':
return Operator::PLUS;
break;
case '-':
return Operator::MIN;
break;
case '*':
return Operator::TIMES;
break;
case '/':
return Operator::DIVIDE;
break;
default:
return Operator::UNDEFINED;
break;
}
}
/*
* Function to do maths on two numbers, the math to do is decided by the operator
* :param x: First number
* :param y: Second number
* :param o: Operator (Plus, Min, Times or Divide)
* :return double: Result of the calculation
*
* Example:
* math(5, 5, Operator::Plus) == 10
*
*/
double math(double x, double y, Operator o) {
double z = 0;
switch (o) {
case Operator::PLUS:
z = x + y;
break;
case Operator::MIN:
z = x - y;
break;
case Operator::TIMES:
z = x * y;
break;
case Operator::DIVIDE:
z = x / y;
break;
}
return z;
}
/*
* Recursive function performing all the calculations from an action string.
* For example, if the string actions has value "5+7" in the first recursive run
* result should contain 12 after the last recursion.
*
* :param result: Double containing the calculated result after the last recursion
* :param actions: Action string (what you type in your calculator; e.g: 5+5). We analyze the first character of this string each time and add it to first_nr, second_nr, or make it the operator. First character gets deleted after each recursion
* :param first_nr: Empty at first recursion, number of left side of the operator. So in 55+77 this paramater will be "55". Gets resetted at the next operator
* :param second_nr: Idem as first_nr but for the right side of the operator.
* :param oper: Operation to calculate the first_nr and second_nr
*/
double calculate(double& result, std::string& actions, std::string& first_nr, std::string& second_nr, Operator& oper) {
//DEBUG OUTPUT:
std::cout << actions << " Gives ";
std::cout << std::to_string(result) << std::endl;
//Base-condition:
//If action string is empty return
if (actions == "") {
//Scenario for when first action is an operator
//e.g: 1+1-
if (second_nr == "")
second_nr = "0";
//Update result
result = math(std::stod(first_nr), std::stod(second_nr), oper);
return result;
}
//Get first character from action string
char c = actions[0];
//Making sure order of math is respected (first times and divdes)
//and than plus and min
char operatorInChar[4] = {'*', '/'};
if (timesAndDividesGone(actions)) {
operatorInChar[2] = '+';
operatorInChar[3] = '-';
}
//If first character is an operator
if (std::find(std::begin(operatorInChar), std::end(operatorInChar), c) != std::end(operatorInChar)) {
//Scenario for when first action is an operator
//e.g: -1+1
if (first_nr == "") {
if (actions[1] == '*')
first_nr = "1";
else
first_nr = "0";
}
//If operator is not yet set in a previous recursion
if (oper == Operator::UNDEFINED) {
oper = charToOperator(c);
//If second_nr is not empty, we need to calculate the two numbers together
if (second_nr != "") {
//Update result
result = math(std::stod(first_nr), std::stod(second_nr), oper);
}
} else {
//Update result
result = math(std::stod(first_nr), std::stod(second_nr), oper);
first_nr = std::to_string(result);
second_nr = "";
//Remove first character from action string because it's analysed in this recursion
actions = actions.erase(0, 1);
oper = charToOperator(c);
return calculate(result, actions, first_nr, second_nr, oper);
}
} else {
//If the character is not a operator but a number we append it to the correct nr
//we add to first_nr if the operator is not yet set, if we already encountered an operator
//we add to second_nr.
//e.g: actions = "123+789"
if (oper == Operator::UNDEFINED) {
first_nr += c;
} else {
second_nr += c;
}
}
//Remove first character from action string because it's analysed in this recursion
actions = actions.erase(0, 1);
//DEBUG OUTPUT:
//std::cout << first_nr << operatorToChar(oper) << second_nr << std::endl;
//std::cout << std::endl << actions << " Gives ";
//std::cout << std::to_string(result) << std::endl;
//Make recursive call
return calculate(result, actions, first_nr, second_nr, oper);
}
int main() {
//String we want to calculate
std::string str = "1*2-2*3";
std::string str_copy_for_output = str;
//Variables
double result = 0;
std::string first_nr = "";
std::string second_nr = "";
Operator oper = Operator::UNDEFINED;
//Call function
int calculation = calculate(result, str, first_nr, second_nr, oper);
//Output
std::cout << std::endl << str_copy_for_output << " = " << calculation << std::endl;
return 0;
}
tl;dr
This code works perfectly for strings only containing plusses and mins or only times and divides. Combining times and divides messes it up. Probably the operator parameter fails to update. How to fix this?
I'm sorry if I did not not analyze your code in detail because it is way too much complicated for what you are trying to do. Therefore I will not tell you where is exactly the problem, instead I will propose you something more simple.
One way or another you need to manage a stack because an algebraic expression must be handled as a tree structure and the evaluation process has to follow that structure. It can't be handled as a flat structure and you can't escape the management of operator precedence. In addition to that an expression is normally evaluated from left to right (left associativity).
That said if you really don't want to use a parsing tool (which IMHO would be more simple and clean), it is always possible to parse "manually". In that case you may avoid to manage an explicit stack by using the call stack itself as demonstrated in the following code:
#include <iostream>
int precedenceOf(char op) {
switch (op) {
case '+':
case '-':
return 4;
case '*':
case '/':
return 3;
}
return 0; // never happen
}
const int MAX_PRECEDENCE = 4;
double computeOp(double left, double right, char c) {
switch (c) {
case '+': return left + right;
case '-': return left - right;
case '*': return left * right;
case '/': return left / right;
}
return 0; // never happen
}
char readOperator(const char*& expr)
{
// read the operator
while (*expr != 0) {
switch (*expr) {
case '+':
case '-':
case '*':
case '/':
{
char res = *expr;
expr++;
return res;
}
case ' ':
break;
}
expr++;
}
return 0;
}
double readOperand(const char*& expr)
{
double result = 0;
while (*expr != 0 && *expr == ' ') expr++;
while (*expr != 0) {
if (*expr >= '0' && *expr <= '9')
result = result * 10 + *expr - '0';
else
return result;
expr++;
}
return result;
}
double eval(const char*& expr, int breakPrecedence = MAX_PRECEDENCE + 1);
// evalRight function reads the right part of an expression and evaluates it
// (up to the point where an operator with precedence 'breakPrecedence' is reached)
// returns the computation of the expression with the left operand passed as parameter.
double evalRight(const char*& expr, int breakPrecedence, double leftOperand)
{
do
{
auto posBeforeOp = expr;
auto op = readOperator(expr);
if (op == 0)
return leftOperand; // end of expression reached, meaning there is no right part
auto prec = precedenceOf(op);
if (prec >= breakPrecedence)
{
expr = posBeforeOp; // we backtrack before the operator (which will be handled by one of our caller)
return leftOperand;
}
// reads and evaluates the expression on the right hand side
auto rightOperand = eval(expr, prec);
// computes the current operation, the result becoming the new left operand of the next operation
leftOperand = computeOp(leftOperand, rightOperand, op);
} while (true);
}
// eval function reads an expression and evaluates it (evaluates it up to the point where an operator with precedence 'breakPrecedence' is reached)
// returns the evaluation of the expression
double eval(const char*& expr, int breakPrecedence)
{
auto leftOperand = readOperand(expr);
return evalRight(expr, breakPrecedence, leftOperand);
}
int main()
{
auto expression = "1 + 1 * 2 - 2 * 3 + 1";
std::cout << "result = " << eval(expression); // prints: result = -2
return 0;
}
To keep the code as simple as possible the provided expression is assumed to be syntactically correct. It's up to you to add some checks if you want.
Hope this helps.
As you said
I'd like to craft something of my own, this is not production-code. Just hobby.
so probably you want to learn a thing or two. That's why I won't write any code here and steal all the fun from you.
Looks like you should start from the basics. I could've recommend you the Dragon Book but you probably want to get your hands dirty right away instead of reading the classics for a week. So you can start with PEGs - it's really simple.
I've started to love parsing after I've read this article.
In your case the grammar will be quite simple:
Expr ← Sum
Sum ← Product (('+' / '-') Product)*
Product ← Value (('*' / '/') Value)*
Value ← [0-9]+
With functions you can rewrite it like this
value = repeat_at_least_once(character("0"),...,character("9"))
product = sequence(value , repeat(one_of(character("*"),character("/")), value )
expr = sequence(product, repeat(one_of(character("+"),character("-")), product)
All you have to do now - write these functions :) It will be not much longer than the code you've written, if not shorter.
If you fill confident, you can even implement packrat parsing with left recursion support, in this case you grammar will be even simpler.
IMHO, your current approach (doing multiplications and divisions first, then continuing with addition and subtraction, and all in one function) will be painful at best. Your calculate function is very hard to reason about already, because it mixes multiple cases already, e.g.
first pass or second pass (depending on the content of string action, which is the current status of the expression, which you modify from call to call)
first_nr empty/filled
second_nr empty/filled
Now imagine that more operators are added, like ^ and ( and ). I do understand that this is a hobby project. But even if you get this to work one day, you will not be able to understand it a week later.
Since you want to reuse your current code, how about this:
Think about how you yourself (as a human being) would go about this? There are multiple approaches. Independent of the specific algorithm they consist of two parts:
Tokenization (identifying numbers and operators)
Evaluation (combine those numbers and operators)
You are mixing both parts in your code. It would be much simpler for you and anybody you are asking for help if you separated them.
Tokenization is simple (you are doing it already, although I would recommend to treat the expression string as read-only).
Evaluation is more tricky, because you have to think about operator precedence. But again, it helps to think about how you would do it as a human. You might read from left to right. How do you handle that as a person? You might evaluate sub expressions with higher precedence first (as you intend to do now). How do you store the tokens? Think of different data structures. Lists, stacks, or queues for examples.
There are many ways. Once you found one, looking at some literature should be fun.
Enjoy!
While I clearly stated I did not want a postfix solution, I actually realized it's the most sane solution. I made a postfix solution myself with the help of tutorials (and still learnt a lot!). Thanks everyone for the help and suggestions.
#include <iostream>
#include <string>
#include <stack>
/*
* Function to check if a given character is an operator (+, -, *, /) or not
* :param c: Character to check
* :return bool: Returns true if parameter c is an operator
*/
bool isOperator(char c) {
char operators[4] = {'+', '-', '*', '/'};
if (std::find(std::begin(operators), std::end(operators), c) != std::end(operators)) {
return true;
}
return false;
}
/*
* Function to get the precedence matching the character
*
* :param a: Character containing the operator to get precedence from
* :return int: Integer representing precedence. Operators with high precedence (e.g * and /) return a higher value than e.g + and -.
*
* Example:
* precedence('*') > precedence('+') == true
*
*/
int precedence(char a) {
switch (a) {
case '+': return 1;
break;
case '-': return 1;
break;
case '*': return 2;
break;
case '/': return 2;
break;
}
return -1;
}
/*
* Function to convert an infix string to postfix notation
* :param infix: Infix string
* :return string: returns postfix string
*
* Example:
* std::string s = "5+5";
* toPostfix(s) == "5 5 +"
*
*/
std::string toPostfix(std::string& infix) {
std::string postfix = "";
//Stack to hold operators and nr is a helper string to
//group digits in numbers
std::stack<char> stack;
std::string nr = "";
//If first character is a minus-operator (AKA a negative number)
//add "0"
if (infix[0] == '-') {
infix = "0" + infix;
}
//Looping over infix string
for (int i = 0; i < infix.size(); i++) {
//If current evaluated character ain't an operator, it's a digit
if (!isOperator(infix[i])) {
//If digit is in a group of digits (AKA a number) put the whole number in nr
while (!isOperator(infix[i]) && i < infix.size()) {
nr += infix[i];
i++;
}
i--;
//Append the number to the postfix string
postfix += nr + " ";
nr = "";
} else {
//This block is executed when evaluated character is an operator
//If stack is empty, or the evaluated operator is higher than the one in the stack
//push it to the stack (Needs to be appended to the postfix string later)
if (stack.size() == 0 || precedence(infix[i]) > precedence(stack.top())) {
stack.push(infix[i]);
} else {
//While the stack contacts a higher or equally high precedence as currently
//evaluated operator
while (precedence(stack.top()) >= precedence(infix[i])) {
//We append the top of the stack to the postfix string
postfix += stack.top();
postfix += ' ';
stack.pop();
if (stack.size() == 0) {
break;
}
}
//Push evaluated operator to stack
stack.push(infix[i]);
}
}
}
//Append all remaining operators to the postfix string
while (stack.size() != 0) {
postfix += stack.top();
stack.pop();
}
return postfix;
}
/*
* Evaluate two numbers regaring the used operator
* :param x: First number to do evaluation with
* :param y: Second number to do evaluation with
* :param _operator: Operator to do calculation with
* :return double: Result of the evaluation
*
* Example:
* x: 5
* y: 60
* _operator: +
* = 65
*/
double evaluate(double x, double y, char _operator) {
switch(_operator) {
case '+':
return x + y;
break;
case '-':
return x - y;
break;
case '*':
return x * y;
break;
case '/':
return x / y;
break;
}
return 0;
}
/*
* Calculate the result of an infix string
* :param s: String containing the infix notation
* :return double: Result of the calculation
*
* Example:
* std::string s = "5+5";
* calculate(s) == 10
*/
double calculate(std::string& s) {
//Convert infix to postfix
s = toPostfix(s);
//Stack holding operators and nr (string) for separating numbers
std::stack<double> stack;
std::string nr = "";
//Looping over postfix string
for (int i = 0; i < s.size(); i++) {
if (s[i] == ' ') {
continue;
}
//If evaluated character is a digit,
//put it in nr
if (isdigit(s[i])) {
//If digit is first of a group of digits, put that group of digits
//AKA a number in nr
while (isdigit(s[i])) {
nr += s[i];
i++;
}
i--;
//Pushing nr in stack
stack.push(std::stod(nr));
nr = "";
} else {
//If current evaluated character is not a digit
//but an operator, do a calculation
//Retrieve first number for calculation
int x = stack.top();
stack.pop();
//Retrieve second number for calculation
int y = stack.top();
stack.pop();
//Put evaluation result in integer and push into stack
int result = evaluate(y, x, s[i]);
stack.push(result);
}
}
//Final number is in stack
return stack.top();
}
int main() {
std::string s = "-5*5-2*2+3-10/5";
std::cout << calculate(s) << std::endl;
}
you need divided calculation for several steps
copy expression to writable memory and check/normalize it:
.check that all chars valid (positive)
.remove spaces
.convert all to low (or upper) case (if case you use hex expressions)
.some operators take 2 symbols ( ==, !=, >=, <=, <<, >>, ||, && ) - replace it to single symbol, from not valid (negative) range
remove ( ) if exist - calculate expressions in ():
.find first ) symbol from begin
.find last ( before it.
.check that after ) and before ( was separator symbols (operator or begin/end of string) but not digit.
.format new string where you replace (..) with it digital result
remove (calculate) all unary operators (+, -, !, ~)
.unary operators - on right side must have digit and on left - another operator(or begin of string), but not digit
.format new string with result of unary operator
remove (calculate) all binary operators.
.we need calculate in reverse precedence - so first need calculate/remove operators with lowest precedence.
.so need do loop by operators (from low to high precedence) - search operator symbol in string.
.if found - A op B - calculate separate A and B and then apply op.
convert string to integer
.now, after all ( ) and operators removed - only digit must be in string
example of code:
namespace Eval
{
typedef INT_PTR (* fn_b_op)(INT_PTR a, INT_PTR b);
typedef INT_PTR (* fn_u_op)(INT_PTR a);
struct b_op_arr { fn_b_op pfn; char c; };
struct u_op_arr { fn_u_op pfn; char c; };
struct name_to_char { char b[3]; char c;};
static INT_PTR fn1_bnt(INT_PTR a){ return !a; }
static INT_PTR fn1_not(INT_PTR a){ return ~a; }
static INT_PTR fn1_add(INT_PTR a){ return +a; }
static INT_PTR fn1_sub(INT_PTR a){ return -a; }
static INT_PTR fn2Land(INT_PTR a,INT_PTR b){ return a && b; }
static INT_PTR fn2_Lor(INT_PTR a,INT_PTR b){ return a || b; }
static INT_PTR fn2_equ(INT_PTR a,INT_PTR b){ return a == b; }
static INT_PTR fn2_nqu(INT_PTR a,INT_PTR b){ return a != b; }
static INT_PTR fn2_lqu(INT_PTR a,INT_PTR b){ return a < b; }
static INT_PTR fn2_gqu(INT_PTR a,INT_PTR b){ return a > b; }
static INT_PTR fn2_leu(INT_PTR a,INT_PTR b){ return a <= b; }
static INT_PTR fn2_geu(INT_PTR a,INT_PTR b){ return a >= b; }
static INT_PTR fn2_add(INT_PTR a,INT_PTR b){ return a + b; }
static INT_PTR fn2_sub(INT_PTR a,INT_PTR b){ return a - b; }
static INT_PTR fn2_mul(INT_PTR a,INT_PTR b){ return a * b; }
static INT_PTR fn2_div(INT_PTR a,INT_PTR b){ return a / b; }
static INT_PTR fn2_dv2(INT_PTR a,INT_PTR b){ return a % b; }
static INT_PTR fn2_lsh(INT_PTR a,INT_PTR b){ return (UINT_PTR)a << b; }
static INT_PTR fn2_rsh(INT_PTR a,INT_PTR b){ return (UINT_PTR)a >> b; }
static INT_PTR fn2_xor(INT_PTR a,INT_PTR b){ return a ^ b; }
static INT_PTR fn2_and(INT_PTR a,INT_PTR b){ return a & b; }
static INT_PTR fn2__or(INT_PTR a,INT_PTR b){ return a | b; }
enum /*: char*/ { equ = -0x80, not_equ, less_equ, gre_equ, l_or, l_and, r_shift, l_shift };
inline static b_op_arr b_arr[] =
{
{fn2_mul, '*'}, {fn2_div, '/'}, {fn2_lsh, l_shift}, {fn2_rsh, r_shift},
{fn2_xor, '^'}, {fn2_dv2, '%'}, {fn2_and, '&'}, {fn2__or, '|'},
{fn2_equ, equ}, {fn2_nqu, not_equ}, {fn2_lqu, '<'}, {fn2_gqu, '>'},
{fn2_leu, less_equ},{fn2_geu, gre_equ},{fn2_add, '+'}, {fn2_sub, '-'},
{fn2Land, l_and}, {fn2_Lor, l_or}
};
inline static u_op_arr u_arr[] =
{
{fn1_add, '+'}, {fn1_sub, '-'}, {fn1_bnt,'!'}, {fn1_not,'~'}
};
inline static name_to_char _2_to_1[] =
{
{"==", equ}, {"!=", not_equ}, {"<=", less_equ}, {">=", gre_equ },
{">>", r_shift}, {"<<", l_shift}, {"||", l_or}, {"&&", l_and},
};
void initBits(LONG bits[], const char cc[], ULONG n)
{
do
{
_bittestandset(bits, cc[--n]);
} while (n);
}
static bool IsSeparatorSymbol(char c)
{
static LONG bits[8];
static bool bInit;
if (!bInit)
{
// acquire
static const char cc[] = {
'*', '/', '+', '-', '^', '%', '&', '|', '<', '>', '!', '~', '(', ')',
equ, not_equ, less_equ, gre_equ, l_or, l_and, r_shift, l_shift, 0
};
initBits(bits, cc, _countof(cc));
// release
bInit = true;
}
return _bittest(bits, c);
}
static bool IsUnaryOpSymbol(char c)
{
static LONG bits[8];
static bool bInit;
if (!bInit)
{
// acquire
static char cc[] = {
'+', '-', '!', '~'
};
initBits(bits, cc, _countof(cc));
// release
bInit = true;
}
return _bittest(bits, c);
}
static bool IsDigit(char c)
{
static LONG bits[8];
static bool bInit;
if (!bInit)
{
// acquire
static char cc[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
initBits(bits, cc, _countof(cc));
// release
bInit = true;
}
return _bittest(bits, c);
}
__int64 strtol64_16(char* sz, char** psz)
{
__int64 r = 0;
while (char c = *sz)
{
ULONG d;
if ((ULONG)(c - '0') <= '9' - '0')
{
d = (c - '0');
}
else if ((ULONG)(c - 'a') <= 'z' - 'a')
{
d = (c - 'a') + 10;
}
else
{
break;
}
r = (r << 4) + d;
sz++;
}
*psz = sz;
return r;
}
bool Normalize(const char* psz, char* buf, size_t s)
{
int len = 0;
do
{
--s;
char c = *psz++, d;
// is valid char
if (c < 0) return false;
// skip space
if (c == ' ') continue;
if ((ULONG)(c - 'A') < (ULONG)('Z' - 'A'))
{
c += 'a' - 'A';
}
// not last char
if (s)
{
d = *psz;
int k = _countof(_2_to_1);
do
{
if (_2_to_1[--k].b[0] == c && _2_to_1[k].b[1] == d)
{
c = _2_to_1[k].c, psz++, --s;
break;
}
} while (k);
}
*buf++ = c, len++;
} while (s);
return 0 < len;
}
char* format_new_str(const char* a, INT_PTR r, const char* b)
{
static const char format[] = "%s%I64x%s";
int len = _scprintf(format, a, r, b);
if (0 < len)
{
if (char* buf = new char [++len])
{
if (0 < sprintf_s(buf, len, format, a, r, b))
{
DbgPrint("++%p\n\"%s\"\n", buf, buf);
return buf;
}
delete buf;
}
}
return 0;
}
bool _calc (char* str, INT_PTR& result)
{
DbgPrint("\"%s\"\n", str);
struct SB
{
char* str;
SB() : str(0) {}
~SB()
{
operator <<(0);
}
void operator <<(char* psz)
{
if (str)
{
DbgPrint("--%p\n", str);
delete [] str;
}
str = psz;
}
} sb;
size_t len = strlen(str);
if (!len)
{
return false;
}
char b, c;
int l;
INT_PTR r, q;
//1. remove ( )
char *psz = str, *pc = 0, *buf;
for (;;)
{
switch (*psz++)
{
case '(':
pc = psz;
continue;
case ')':
if (!pc || !IsSeparatorSymbol(*psz) || (pc > str + 1 && !IsSeparatorSymbol(pc[-2]))) return false;
psz[-1] = 0, pc[-1] = 0;
if (_calc(pc, r) && (buf = format_new_str(str, r, psz)))
{
sb << buf;
psz = str = buf, pc = 0;
continue;
}
return false;
case 0:
goto __2;
}
}
__2:
//2. remove unary op
psz = str;
do
{
if (IsDigit(c = *psz) && str < psz && IsUnaryOpSymbol(c = psz[-1]) && (psz == str + 1 || IsSeparatorSymbol(psz[-2])))
{
psz[-1] = 0;
l = _countof(u_arr);
do
{
if (u_arr[--l].c == c)
{
r = strtol64_16(psz, &psz);
if (IsSeparatorSymbol(*psz))
{
r = u_arr[l].pfn(r);
if (buf = format_new_str(str, r, psz))
{
sb << buf;
psz = str = buf;
goto __2;
}
}
break;
}
} while (l);
return false;
}
} while (psz++, c);
//3. remove binary op
l = _countof(b_arr);
do
{
c = b_arr[--l].c;
psz = str;
do
{
if (c == (b = *psz++))
{
psz[-1] = 0;
if (_calc(psz, q) && _calc(str, r))
{
result = b_arr[l].pfn(r, q);
return true;
}
return false;
}
} while (b);
} while (l);
result = strtol64_16(str, &str);
return !*str;
}
bool calc(const char* psz, INT_PTR& result)
{
bool fOk = false;
if (size_t s = strlen(psz))
{
if (char* buf = new char[++s])
{
if (Normalize(psz, buf, s))
{
fOk = _calc(buf, result);
}
delete [] buf;
}
}
return fOk;
}
};
use
INT_PTR r;
Eval::calc(str, r);
While reading Learning Go I've implemented some of the suggested training programs. One of which has nearly the same requirements as yours, although I have to admit, that yours is a bit more evolved. So, I hope you can get something out of this code (I know it's not C++, but I'm sure you can read it):
package main
import (
"fmt"
"os"
"bufio"
"stack"
"strconv"
)
func readInput() string {
reader := bufio.NewReader(os.Stdin)
switch in, ok := reader.ReadString('\n'); true {
case ok != nil:
fmt.Printf("Failed to read inputs: %v", ok)
return "error"
default:
return in[:len(in)-1]
}
}
func isdigit(in string) bool {
_,ok := strconv.Atoi(in)
return ok == nil
}
func isOperation(in string) bool {
chars := []rune(in)
return '+' == chars[0] || '-' == chars[0] || '*' == chars[0] || '/' == chars[0]
}
func calc(operation string, op2, op1 int) float32 {
chars := []rune(operation)
switch chars[0] {
case '+':
return float32(op1 + op2)
case '-':
return float32(op1 - op2)
case '*':
return float32(op1 * op2)
case '/':
return float32(op1) / float32(op2)
}
print("Failed to recognize operation: ")
println(operation)
fmt.Printf("%v\n", chars)
return 0.0
}
func main() {
var st stack.Stack
fmt.Println("Calculator.")
fmt.Println("Please input operations and then one of + - * / for calculation,")
fmt.Println("or anything else for exit.")
LOOP: for {
in := readInput()
switch {
case isdigit(in):
i,_ := strconv.Atoi(in)
st.Push(i)
case isOperation(in):
op2 := st.Pop()
op1 := st.Pop()
res := calc(in, op2, op1)
st.Push(int(res))
fmt.Println(res)
default:
fmt.Println("Exit")
break LOOP
}
}
}
... similar, isn't it?

char array c++ vowels

I am trying to make a program that will use a switch statement and see if an element of a char array is a vowel and which one, but i am stuck at how to check the elements:
int prob2() {
char uName[25] = "";
int voCo = 0;
cout<<"Enter you first and last name, under 25 chars please: ";
cin>>uName;
int i = 0;
while(i <= 25){
switch(i){
case 1:
voCo++;
break;
case 2:
voCo++;
break;
case 3:
voCo++;
break;
case 4:
voCo++;
break;
case 5:
voCo++;
break;
default:
break;
}
i++;
}
cout<<"Your first and last name have: "<<voCo<<" vowels in them."<<endl;
return 0;
}
It seems you mean the following
#include <iostream>
#include <cctype>
using namespace std;
//...
size_t prob2()
{
const size_t N = 25;
char uName[N] = "";
size_t voCo = 0;
cout<<"Enter you first and last name, under " << N << " chars please: ";
cin.getline( uName, N );
for ( char *p = uName; *p != '\0'; ++p ) *p = toupper( ( unsigned char )*p );
for ( const char *p = uName; *p != '\0'; ++p )
{
switch( *p )
{
case 'A':
voCo++;
break;
case 'E':
voCo++;
break;
case 'I':
voCo++;
break;
case 'O':
voCo++;
break;
case 'U':
voCo++;
break;
default:
break;
}
}
cout<<"Your first and last name have: "<<voCo<<" vowels in them."<<endl;
return voCo;
}
You could try something like this:
const std::string vowels = "aeiou";
const std::string name = "martin luther king, jr.";
const unsigned int name_length = name.length();
unsigned int vowel_count = 0U;
for (unsigned int i = 0U; i < name_length; ++i)
{
if (vowels.find(name[i]) != std::string::npos)
{
++vowel_count;
}
}
No need for switch statement. This is one of many possible algorithms or implementations.
Edit 1: An array of counts
You could also use an array of counts:
unsigned int counts[26] = {0};
for (unsigned int i = 0U; i < name_length; ++i)
{
const c = std::tolower(name[i]);
if (isalpha(c))
{
counts[c - 'a']++;
}
}
const unsigned int vowel count =
counts['a'] + counts['e'] + counts['i']
+ counts['o'] + counts['u'];
First of all decouple user interaction from the logic solving your requirement. I think we can safely assume you can collect the input in this case and save it into an string. So we will not waste our time with that.
We will focus on developing and testing the code that solves the requirement. In a standard C++. Now here is the deep end of the pool. The code.
// mike.h
#pragma once
// std::string view requires C++17
#include <string_view>
// always use namespace,to avoid name clashes
namespace mike {
// make 'sv' the string_view literal available
using namespace std::string_view_literals;
// declare and define compile time
// string view literal
// 'constexpr' guarantees compile time
// notice the use of 'sv'
constexpr auto vowels = "eaiouEAIOU"sv;
// compile time function to count literals
// again 'constexpr' guarantees compile time
// inline gurantees we can include this header many times
// without making accidental duplicates of `count_vowels`
// 'in_' argument has 'std::string_view' passed by value
// pass by value is preferred standard C++ method
// of functions arguments passing
// 'std::string_view' is standard C++ preferred type
// to pass strings into functions
inline constexpr size_t
count_vowels(std::string_view in_)
{
// return type is size_t
// we can count very large number of vowels
// but all at compile time
size_t rezult{};
// this is C+17 'range for'
// we cast implicitly references to input elements
// from, `char const &` to `int const &`
// cost of that is very likely 0
for (int const & ch_ : in_)
for (int const & v_ : vowels)
// there is no if() here
// we simply add 0's or 1's, to the rezult
// false is 0, true is 1
// the correct by the book way of coding that is
// static cast from bool to int
// rezult += static_cast<int>( v_ == ch_ ) ;
rezult += v_ == ch_ ;
return rezult;
}
// runtime speed of this call is 0 (zero)
// all happens at compile time
// notice how we pass normal string literal
// no need to create string_view
constexpr size_t r1
= count_vowels("abra ca dabra");
// no runtime tests necessary
// `static_assert()` is compile time assert
// failure message is optional
static_assert(r1 == 5,
"compile time calculation failed, 'abra ca dabra', must contain 5 vowels");
} // mike ns
Hopefully there are a lots of comments. Solution does not use switch() statement or if() statements. Thanks to standard C++ constructs, code is very simple, resilient and probably very fast when compiled by modern optimizing compilers.
Solution works at compile time too. That is not stopping you to use it in your run-time scenario. Although, I would advise again using native char array. std::string might be a perfect match here.
std::string input_ = collect_user_input() ;
int rezult = count_vowels(input_);
Enjoy the standard C++ ...

how to convert returned ascii arithmetic symbols, so it can be used with operands

How could I use arithmetic operation symbols if its assigned to variable and need to return for evaluation of simple arithmetic problems --> from the way its constructed in the code below. How? or any other suggestions welcomed thanks in advance
int arithmeticType();
int main() {
int arithmeticSymbol = arithmeticType();
int x, y;
int result = 0;
srand(time(NULL) );
printf( "Type is: %d\n", arithmeticSymbol );
//how to get result of (x + y)using arithmeticSymbol?????
printf( "The result %d %d %d", 4, arithmeticSymbol, 3 );
return 0;
}
int arithmeticType() {
int type, token;
printf("Select the type of arithmetic operation to perform:\n"
"\t1. Addition.\n\t2. Subtraction.\n\t3. Multiplication.\n\t"
"4. Mixture of all three. --> ");
scanf("%d", &type);
switch ( type ) {
case 1:
token = '+';
break;
case 2:
token = '-';
break;
case 3:
token = '*';
break;
case 4:
//get random value between 1-3
token = rand() % 3 + 1;
if ( token == 1 ) {
token = '+';
}
else if ( token == 2 ) {
token = '-';
}
else {
token = '*';
}
break;
default:
printf("Wrong input");
break;
}
return token;
}
Write a function to apply the operator. You also need to consider your types - if you just use integers, things like 3/2 may not do what you expect...
If it was me I'd probably use an enum instead of the ASCII operator code.
int getResult(int op1, int op, int op2)
{
int result = 0;
if (op== '+') {
result = op1 + op2;
}
else ...
return result;
}
You would call it like: printf( "The result of %d %c %d is: %d", 4, getOperation, 3, getResult(4, getOperation, 3) ); (note printing the operator as %d wont do what you expect and the name getOperator is very misleading.

string conversion c++

I have a string and the first element is for example 'a'. I already declared a variable called a ( so int a=1 for example). My question now is, how can I convert the whole string to numbers (a=1,b=2,c=3,...z=26)? Example:
string str="hello"; this has to be changed to "85121215" and then changed to 85121215.
// transformation itself doesn't care what encoding we use
std::string transform_string(std::string const &in, std::function<int(char)> op)
{
std::ostringstream out;
std::transform(in.begin(), in.end(),
std::ostream_iterator<int>(out),
op);
return out.str();
}
// the per-character mapping is easy to isolate
int ascii_az_map(char ch)
{
if (ch < 'a' || ch > 'z') {
std::ostringstream error;
error << "character '" << ch << "'=" << (int)ch
<< " not in range a-z";
throw std::out_of_range(error.str());
}
return 1 + ch - 'a';
}
// so we can support other encodings if necessary
// NB. ebdic_to_ascii isn't actually implemented here
int ebcdic_az_map(char ch)
{
return ascii_az_map(ebcdic_to_ascii(ch));
}
// and even detect the platform encoding automatically (w/ thanks to Phresnel)
// (you can still explicitly select a non-native encoding if you want)
int default_az_map(char ch)
{
#if ('b'-'a' == 1) && ('j' - 'i' == 1)
return ascii_az_map(ch);
#elif ('j'-'i' == 8)
return ebcdic_az_map(ch);
#else
#error "unknown character encoding"
#endif
}
// use as:
std::string str = "hello";
std::string trans = transform_string(str, ascii_az_map);
// OR ... transform_string(str, ebcdic_az_map);
Note that since the per-character mapping is completely isolated, it's really easy to change the mapping to a lookup table, support different encodings etc.
Your definition is a bit small:
"hello" = "85121215
h = 8
e = 5
l = 12
o = 15
I assume you mean that
a = 1
b = 2
...
z = 26
in which case it is not that hard:
std::string meh_conv(char c) {
switch(c) { // (or `switch(tolower(c))` and save some typing)
case 'a': case 'A': return "1";
case 'b': case 'B': return "2";
....
case 'z': case 'Z': return "26";
....
// insert other special characters here
}
throw std::range_error("meh");
}
std::string meh_conv(std::string const &src) {
std::string dest;
for (const auto c : s)
dest += meh_conv(c);
return dest;
}
or use std::transform():
#include <algorithm>
std::string dest;
std::transform (src.begin(), src.end(), back_inserter(dest),
meh_conv)
(doesn't work for different incoming and outgoing types, at least not as is)
Addendum.
You possibly want to parametrize the replacement map:
std::map<char, std::string> repl;
repl['a'] = repl['A'] = "0";
repl[' '] = " ";
std::string src = "hello";
std::string dest;
for (const auto c : src) dest += repl[c];
I wrote you a simple example. It creates a map what contains the a-1, b-2, c-3 ... pairs. Then concatenate the values using a stringstream:
#include <iostream>
#include <map>
#include <sstream>
int main()
{
std::string str = "abc";
std::map<char,int> dictionary;
int n = 1;
for(char c='a'; c<='z'; c++)
dictionary.insert(std::pair<char,int>(c,n++));
//EDIT if you want uppercase characters too:
n=1;
for(char c='A'; c<='Z'; c++)
dictionary.insert(std::pair<char,int>(c,n++));
std::stringstream strstream;
for(int i=0; i<str.size(); i++)
strstream<<dictionary[str[i]];
std::string numbers = strstream.str();
std::cout<<numbers;
return 0;
}
C++ experts probably going to kill me for this solution, but it works ;)
Easy Approach,
you can find mod of char with 96 (ASCII value before a), as result it will always give you values in range 1-26.
int value;
string s;
cin>>s;
for(int i=0; i<s.size();i++){
value = s[j]%96;
cout<<value<<endl;
}