質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

492閲覧

数値を基数変換して表示したい

eipi-1-0

総合スコア8

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2022/11/15 08:19

前提

c++で数値を基数変換し格納、表示するクラスを作っています

実現したいこと

コンストラクタ
数値を入力し、n進数の各桁を配列に格納したい

発生している問題・エラーメッセージ

2進数で1が連続した値 (2^n - 1) が出力され、正しく基数変換できない

問題があると思われるコードを抜粋、修正したものです
入力された数値を2進数で逆順に出力する(ことを期待したい)コードです

c++

1#include <cstdint> 2#include <iostream> 3int main(){ 4 uint64_t num; 5 std::cin >> num; 6 for(uint8_t i = 0; i < 64; i++){ 7 std::cout << (num != (num >>= 1) << 1); // 問題箇所 8 } 9 std::cout << std::endl; 10 return 0; 11}

該当のソースコード

c++

1// main.cpp 2#include <cstdint> 3#include <iostream> 4#include "base.hpp" 5int main(){ 6 uint64_t a; 7 std::cin >> a; 8 std::cout << Base(2, a) << std::endl; 9 return 0; 10}

c++

1// base.hpp 2#ifndef base_hpp 3#define base_hpp 4#include <cstdint> 5#include <iostream> 6class Base{ 7 char* number; 8 uint64_t base; 9 uint64_t* num; 10 uint64_t digit; 11 void add(uint64_t* base_a, const uint64_t* base_b); 12public: 13 Base(const char* number, uint64_t num, uint64_t digit = 64); 14 Base(uint64_t base, uint64_t num, uint64_t digit = 64); 15 friend std::ostream& operator<<(std::ostream& os, Base base_a); 16}; 17#endif

c++

1// base.cpp 2#include "base.hpp" 3void Base::add(uint64_t* base_a, const uint64_t* base_b){ 4 uint8_t carry = 0; 5 for(uint64_t i = 0; i < digit; i++){ 6 uint64_t temp = base_a[i] + base_b[i] + carry; 7 carry = temp < base_a[i] + carry || base <= temp; 8 base_a[i] = carry? temp - base: temp; 9 } 10 return; 11} 12Base::Base(const char* number, uint64_t num, uint64_t digit): 13base(0), num(new uint64_t[digit]{}), digit(digit){ 14 while(number[base]) base++; 15 this->number = new char[base]; 16 for(uint64_t i = 0; i < base; i++){ 17 this->number[i] = number[i]; 18 } 19 uint64_t* twice = new uint64_t[digit]{1}; 20 if(num != (num >>= 1) << 1) add(this->num, twice); // 問題箇所 21 for(uint64_t i = 1; i < digit; i++){ 22 add(twice, twice); 23 if(num != (num >>= 1) << 1) add(this->num, twice); // 問題箇所 24 } 25 return; 26} 27Base::Base(uint64_t base, uint64_t num, uint64_t digit): 28number(new char[base]{}), base(base), num(new uint64_t[digit]{}), digit(digit){ 29 const char number[] = 30 "0123456789" 31 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 32 "abcdefghijklmnopqrstuvwxyz"; 33 for(uint64_t i = 0; i < base && i < 62; i++){ 34 this->number[i] = number[i]; 35 } 36 uint64_t* twice = new uint64_t[digit]{1}; 37 if(num != (num >>= 1) << 1) add(this->num, twice); // 問題箇所 38 for(uint64_t i = 1; i < digit; i++){ 39 add(twice, twice); 40 if(num != (num >>= 1) << 1) add(this->num, twice); // 問題箇所 41 } 42 return; 43} 44std::ostream& operator<<(std::ostream& os, Base base_a){ 45 uint64_t digit = base_a.digit; 46 uint64_t i = 0; 47 for(; i < digit; i++) if(base_a.num[digit - i - 1]) break; 48 if(i == digit) os << base_a.number[0]; 49 else for(; i < digit; i++) os << base_a.number[base_a.num[digit - i - 1]]; 50 return os; 51}

試したこと

問題箇所の式を次のように変更したところ、うまく動作しました

c++

1// uint64_t temp; 2// ... 3((temp = num) != (num >>= 1) << 1);

c++

1(num != num >> 1 << 1); 2num >>= 1;

補足情報(FW/ツールのバージョンなど)

google colaboratory で g++ を使用しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

(num != (num >>= 1) << 1)のような、「代入した変数を、(副作用完了点を超えない)同じ式の別の場所で参照するコード」は、C++では評価順が決まっておらず、未定義の動作となります。

素直に、numのシフトとビットごとの評価を別な式で行いましょう。

投稿2022/11/15 08:37

編集2022/11/15 08:39
maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

eipi-1-0

2022/11/15 09:03

なるほど、式の始めの位置以外での代入の使用や、1つの式の中で複数の代入を行うことは良い書き方ではないのですね 早急なご回答ありがとうございました。大変助かりました
maisumakun

2022/11/15 09:10

> 式の始めの位置以外での代入の使用や、1つの式の中で複数の代入を行うことは良い書き方ではないのですね どちらも微妙に外しているのですが…(特に、この式には「1つの式の中で複数の代入」は含まれていません)
eipi-1-0

2022/11/16 00:25

分かりにくい書き方をしてしまい申し訳ありません この式に限らず一般的な式の話です。 可読性の低下や未定義動作となる可能性があるためという意図です
maisumakun

2022/11/16 00:31

> この式に限らず一般的な式の話です。 そうであっても、「式の始めの位置以外での代入の使用や、1つの式の中で複数の代入」そのものは未定義の動作にはなりません。あくまで、「同じ変数」を複数回使った場合の問題です。
maisumakun

2022/11/16 00:32

たとえば、a=b=50;のような書き方はよく使われます。
eipi-1-0

2022/12/17 14:44

返信遅れて申し訳ありません なかなか難しいですが理解することができました 丁寧に回答して頂きありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問