Задача на типы данных в C++
Проходит лишь 21 тест из 50. Не понимаю в чем ошибка. Пытался без прямого сравнения с границами, а через логарифмы - не получилось. Помогите, пожалуйста.
Определение подходящих типов:
Дано целое число. Требуется определить все подходящие для его хранения типы данных.
Входные данные:
Входные данные содержат единственное целое число n (−2⁶⁴ ≤ n ≤ 2⁶⁴).
Выходные данные:
Выведите все подходящие типы данных, в которых можно хранить число n.
Если их несколько, то выводите каждый новый тип в отдельной строке.
Типы данных следует выводить в том же порядке, что и в следующем списке:char unsigned char short int unsigned short int int unsigned int long long unsigned long long
Мой код:
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
long long int n;
cin >> n;
if (-256 <= n && n <= 255){
cout << "char\n";
}
if (0 <= n && n <= 511){
cout << "unsigned char\n";
}
if (-65536 <= n && n <= 65535){
cout << "short int\n";
}
if (0 <= n && n <= 131071){
cout << "unsigned short int\n";
}
if (-4294967296 <= n && n <= 4294967295){
cout << "int\n";
}
if (0 <= n && n <= 8589934591){
cout << "unsigned int\n";
}
cout << "long long\n";
if (n >= 0){
cout << "unsigned long long\n";
}
return 0;
}
Переписал код - всё равно не работает:
#include <iostream>
#include <string>
using namespace std;
bool les(string n, string d){
if (n[0] == '-'){
if (d[0] != '-'){
return true;
}
return not les(n.substr(1), d.substr(1));
}else{
if (d[0] == '-'){
return false;
}
if (n.length() < d.length()){
return true;
}
if (n.length() > d.length()){
return false;
}
return n <= d;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
string n;
cin >> n;
if (les("-128", n) && les(n, "127")) cout << "char\n";
if (les("0", n) && les(n, "255")) cout << "unsigned char\n";
if (les("-32768", n) && les(n, "32767")) cout << "short int\n";
if (les("0", n) && les(n, "65535")) cout << "unsigned short int\n";
if (les("-2147483648", n) && les(n, "2147483647")) cout << "int\n";
if (les("0", n) && les(n, "4294967295")) cout << "unsigned int\n";
if (les("-9223372036854775808", n) && les(n, "9223372036854775807")) cout << "long long\n";
if (les("0", n) && les(n, "18446744073709551615")) cout << "unsigned long long\n";
}
Ответы (3 шт):
В старом коде из вопроса были ошибочно заданы границы всех типов. У некоторых типов границы не были заданы вовсе.
В новом коде есть ошибка в строке return not les(n.substr(1), d.substr(1));. Для равных отрицательных значений функция возврадает ложь, а должна истину. Вместо отрицания надо поменять местами аргументы. Справедливость требует заметить, что и я сделал такую же ошибку в своём решении, но потом исправил её.
Идеи для решения:
- получить у компилятора границы типов;
- считать число как строку;
- научиться сравнить числа, заданные строками.
Вот ответ на сравнениях строк:
#include <iostream>
#include <limits>
#include <string>
#include <string_view>
bool le(const std::string_view &a, const std::string_view &b) {
if (a[0] == '-') {
if (b[0] == '-') {
return le(b.substr(1), a.substr(1));
}
return true;
}
if (b[0] == '-') {
return false;
}
if (a.size() < b.size()) {
return true;
}
if (a.size() > b.size()) {
return false;
}
return a <= b;
}
template <typename T>
void check(const char *name, const std::string_view &x) {
static const auto min = std::to_string(std::numeric_limits<T>::min());
static const auto max = std::to_string(std::numeric_limits<T>::max());
if (le(min, x) && le(x, max)) {
std::cout << name << '\n';
}
}
int main() {
std::string n;
std::cin >> n;
check< char>( "char" , n);
check<unsigned char>("unsigned char" , n);
check< short>( "short int" , n);
check<unsigned short>("unsigned short int" , n);
check< int>( "int" , n);
check<unsigned int>("unsigned int" , n);
check< long long>( "long long int", n);
check<unsigned long long>("unsigned long long int", n);
}
$ g++ -std=c++23 -pedantic -Wall -Wextra -Werror -Wwrite-strings -Wconversion temp.cpp $ echo -18446744073709551616 | ./a.out $ echo -9223372036854775809 | ./a.out $ echo -9223372036854775808 | ./a.out long long int $ echo -2147483649 | ./a.out long long int $ echo -2147483648 | ./a.out int long long int $ echo -32769 | ./a.out int long long int $ echo -32768 | ./a.out short int int long long int $ echo -129 | ./a.out short int int long long int $ echo -128 | ./a.out char short int int long long int $ echo 0 | ./a.out char unsigned char short int unsigned short int int unsigned int long long int unsigned long long int $ echo 127 | ./a.out char unsigned char short int unsigned short int int unsigned int long long int unsigned long long int $ echo 128 | ./a.out unsigned char short int unsigned short int int unsigned int long long int unsigned long long int $ echo 255 | ./a.out unsigned char short int unsigned short int int unsigned int long long int unsigned long long int $ echo 256 | ./a.out short int unsigned short int int unsigned int long long int unsigned long long int $ echo 32767 | ./a.out short int unsigned short int int unsigned int long long int unsigned long long int $ echo 32768 | ./a.out unsigned short int int unsigned int long long int unsigned long long int $ echo 65535 | ./a.out unsigned short int int unsigned int long long int unsigned long long int $ echo 65536 | ./a.out int unsigned int long long int unsigned long long int $ echo 2147483647 | ./a.out int unsigned int long long int unsigned long long int $ echo 2147483648 | ./a.out unsigned int long long int unsigned long long int $ echo 4294967295 | ./a.out unsigned int long long int unsigned long long int $ echo 4294967296 | ./a.out long long int unsigned long long int $ echo 9223372036854775807 | ./a.out long long int unsigned long long int $ echo 9223372036854775808 | ./a.out unsigned long long int $ echo 18446744073709551615 | ./a.out unsigned long long int $ echo 18446744073709551616 | ./a.out $
if (-256 <= n && n <= 255){ cout << "char\n"; }
Ну вообще-то char - это
if (-128 <= n && n <= 127) {
Остальные все числа - так же.
В условии есть подозрительные границы про 2**64 включительно - это не влезет в int64, а 2 значения по модулю влезут и в uint64.
Я всё-таки намутил проверку без использования строк с числами не длиннее 64 бит:
#include <cstdio>
int main()
{
int neg, len;
unsigned long long x, y;
scanf(" ");
scanf("-%n", &(neg=0));
scanf("%19llu%n", &x, &len);
if (len == 19 && scanf("%llu", &y) == 1 && !(x=x*10+y))
return 0;
#define CHECK(sign, type) \
do \
{ \
bool sig = (sign type)~(sign type)0 < (sign type)0; \
sign type max = (unsigned type)~(type)0 >> sig; \
\
if (neg ? sig && x-1 <= max : x <= max) \
printf("%s" #type "\n", sig ? "" : #sign " "); \
} \
while(0)
CHECK(signed, char);
CHECK(unsigned, char);
CHECK(signed, short int);
CHECK(unsigned, short int);
CHECK(signed, int);
CHECK(unsigned, int);
CHECK(signed, long long);
CHECK(unsigned, long long);
return 0;
}
Для любителей сомнительных char'ов в духе -funsigned-char:
CHECK(, char);