[ 新規に投稿する ]

[不具合]文字数カウントNo.10435
fzok4234 さん 21/05/26 16:31 [ コメントを投稿する ]
  いつもお世話になっております。

さて、文字数カウント機能において誤った文字数が返される問題が見つかりました。

テストに使ったファイルは、
1行の書式  : U+002Aが2499個連続 + 改行コードLF
行数       : 1000000行
文字コード : Shift-JIS
の2500000000文字、2500000000Byteです。

なお、ファイル読み込みに際しては
https://www.maruo.co.jp/turukame/3/x10410_.html#10410
で挙げた不正終了の不具合を回避するため、「ファイルの一部を開く」機能で「読み込む範囲を指定する」を
ONにして「位置」を最小に、「サイズ」を最大にして開きました。

 1. 「表示」メニューやステータスバーの「文字数計算」機能。
    「文字列」ダイアログの全ての項目を「1文字分」にしたとき、結果が
    -1794967296
    と誤った値になってしまいます。まるで符号付32bit整数がオーバーフローしたような
    結果となっています。
    
    本来、文字数のようなファイルの巨大化に伴って極めて大きくなりうる数値には、
    「符号無し64bit整数」や「倍精度浮動小数点数」などの桁数に余裕のある数値型を
    用いるべきなのですが、文字数処理が内部では本当に符号付32bit整数で行われてしまって
    いるような気がします。

 2. マクロのcharcount()関数。
    以下のように整数モードと浮動小数点数モードでそれぞれ1文字分と2文字分で計算しました。
    
    debuginfo 2 ;
    setfloatmode 0 ;
    debuginfo @"[IntegerMode]" + "\U0000000A" ;
    debuginfo @"X1=" + str( charcount( 0x00000000 ) ) + "\U0000000A" ;
    debuginfo @"X2=" + str( charcount( 0x00111111 ) ) + "\U0000000A" ;
    setfloatmode 1 ;
    debuginfo @"[FloatMode]" + "\U0000000A" ;
    debuginfo @"X1=" + str( charcount( 0x00000000 ) ) + "\U0000000A" ;
    debuginfo @"X2=" + str( charcount( 0x00111111 ) ) + "\U0000000A" ;
    endmacro ;
    
    実行結果は以下の通りです
    
    [IntegerMode]
    X1=-1794967296
    X2=705032704
    [FloatMode]
    X1=2500000000
    X2=705032704
    
    整数モードでは、1文字分と2文字分との両方でオーバーフローが見られますが、元々整数モードでの
    数値変数は符号付32bit整数であるので、これは正しい動作であるようです。一方、浮動小数点数モードでは
    1文字分の方は正しい値となっていますが、2文字分の方は本来
    5000000000
    となるべきところが、なぜか整数モードの2文字分と同じ値になってしまっています。条件次第で
    浮動小数点数モードが勝手に解除されてしまうみたいです。

バージョンはv8.98β9 Float x64です。

[ ]
RE:10435 [不具合]文字数カウントNo.10436
でるもんたいいじま さん 21/05/26 17:34 [ コメントを投稿する ]
  でるもんた・いいじまです。

> さて、文字数カウント機能において誤った文字数が返される問題が見つかりました。

> テストに使ったファイルは、
> 1行の書式  : U+002Aが2499個連続 + 改行コードLF
> 行数       : 1000000行
> 文字コード : Shift-JIS
> の2500000000文字、2500000000Byteです。

1行が改行コミで2500バイト、行数が100万、EOF文字はないとして合計2.5億バイトですね。

ちなみにこちらは訳あって32bit版の秀丸ですが、こちらでもユーザー空間3GBをフルに使えるようですね。設定で128MBになっていたので、一時的に3000MBに上げてみました。

…読むだけで相当に重いです^^

#あと、最大1000万行(64bit版は1億行)の制限って、
#物理行数(画面上の行数)でカウントするんですね。
#これも歴史を感じます。

> 文字数処理が内部では本当に符号付32bit整数で行われて
> しまっているような気がします。

ですね。
…まあ、こういうものは一つずつ地道に潰していくしかないでしょう。

#そういう作業に興味がある人たちだけのML作りますか?
#ちょうど、turukame.8とturukame.9が未使用のまま空いていますし、
#あるいは、turukame.1の今の内容をHTMLにアーカイブしてから
#まっさらにして使い回してもいいですし。

☆ ☆ ☆

以下は釈迦に説法。

☆ ☆ ☆

旧版のVCにいつから uint64_t があるかは確認していませんが、昔からVC独自の組み込み型として__int64、__uint64がありますので(Win32初対応となるVC4.0の時点から既にあったと思う)、VCのバージョンが古くても64bit化は難しくないと思います。

#つまり、イマドキの通例なら #include<stdint.h> の1行で済む内容のうち、
#秀丸に必要な部分だけをうまく再発明すればいいだけのことです。

#逆に、あえて再発明することで「このパラメータは32bit縛りが仕様」
#「このパラメータは完全64bit化済」という情報が、ごく少数のヘッダ
#ファイルに集約されます。うまくやれば、型名の不一致を検出して
#ビットあふれの可能性を予測、なんてこともできるかもしれませんし。

> 本来、文字数のようなファイルの巨大化に伴って極めて大きくなりうる数値には、
> 「符号無し64bit整数」や「倍精度浮動小数点数」などの桁数に余裕のある数値型を
> 用いるべきなのですが、

今回は64bitですかね。64bit型がない時代の環境ならdoubleやむなしですが、doubleは53bitしか有効数字がないので、長期的には不安です。
(たとえば今のご時世で、一般の個人や零細企業などが自前で持てるストレージはせいぜい100TBくらいでしょうけど、YouTubeあたりのデータ総量はもしかしたら既に64bitの範囲を超えているかもしれません。)

それに、文字数まわりの計算はすべて整数演算(一部に1/2を含みますが)なので、doubleだと無駄な型変換が起きてデメリットしかないです。
[ ]
RE:10436 [不具合]文字数カウントNo.10437
秀丸担当 さん 21/05/26 18:13 [ コメントを投稿する ]
 
文字数計算のダイアログ等については確かにその通りでした。
できるように対応していこうと思います。

マクロについては、setfloatmode 0;のときは通常版と同じであったほうがよくて、32bitの正の数の上限までの制限にしたほうがいいかもしれません。
setfloatmode 1;のときで動作を変えるべきかというのは微妙で、全部合わせたほうがいい気もしますが、とりあえずそもそも可能かどうか試してみて検討します。
[ ]
RE:10437 [不具合]文字数カウントNo.10438
こみやんま さん 21/05/26 18:31 [ コメントを投稿する ]
  この辺 int しか想定してないのたくさんあると思いますねぇ。
linenoやcolumnなども int までになってるだろうし...

C関数としてexternしてしまってるものにもそういったものも含まれてるので、なかなかですねこの辺は。
[ ]
RE:10437 [不具合]文字数カウントNo.10439
fzok4234 さん 21/05/26 23:15 [ コメントを投稿する ]
  マクロ仕様において破壊的変更を伴わずに正式に64bit整数をサポートする方法として、通常の32bit数値変数を
2個使って64bit整数の代わりとする方法を用いてもよいのでは、と思いました。つまり、64bitのうち0〜31bitの
下位32bitと32〜64bitの上位32bitの2個の独立した数値変数で1つのペアとすることです。この場合、新たに以下の
例のような文/関数を新設して演算処理などを行うことになるでしょう。

四則演算。
単項+ (文) : unaryplusint64 #lower, #upper, #lowerReturn, #upperReturn ;
単項- (文) : negateint64    #lower, #upper, #lowerReturn, #upperReturn ;
+     (文) : addint64       #lowerleft, #upperleft, #lowerright, #upperright, #lowerReturn, #upperReturn ;
-     (文) : subtractint64  #lowerleft, #upperleft, #lowerright, #upperright, #lowerReturn, #upperReturn ;
*     (文) : multiplyint64  #lowerleft, #upperleft, #lowerright, #upperright, #lowerReturn, #upperReturn ;
/     (文) : divideint64    #lowerleft, #upperleft, #lowerright, #upperright, #lowerReturn, #upperReturn ;
%     (文) : moduloint64    #lowerleft, #upperleft, #lowerright, #upperright, #lowerReturn, #upperReturn ;

bit操作。
^ (文) : notint64 #lower, #upper, #lowerReturn, #upperReturn ;
| (文) : orint64  #lowerleft, #upperleft, #lowerright, #upperright, #lowerReturn, #upperReturn ;
& (文) : andint64 #lowerleft, #upperleft, #lowerright, #upperright, #lowerReturn, #upperReturn ;

比較。戻り値は1か0。
<= (関数) : #result = lessthanorequalint64(    #lowerleft, #upperleft, #lowerright, #upperright ) ;
>= (関数) : #result = greaterthanorequalint64( #lowerleft, #upperleft, #lowerright, #upperright ) ;
<  (関数) : #result = lessthanint64(           #lowerleft, #upperleft, #lowerright, #upperright ) ;
>  (関数) : #result = greaterthanint64(        #lowerleft, #upperleft, #lowerright, #upperright ) ;
!= (関数) : #result = notequalint64(           #lowerleft, #upperleft, #lowerright, #upperright ) ;
=  (関数) : #result = equalint64(              #lowerleft, #upperleft, #lowerright, #upperright ) ;

変換。
Int32=>Int64        (文)   : int32toint64 #int32, #lowerReturn, #upperReturn ;
Int64=>Int32        (関数) : #int32 = int64toint32( #lower, #upper ) ;
文字列=>Int64       (文)   : valint64 $str, #lowerReturn, #upperReturn ;
Int64=>10進数文字列 (関数) : $dec = strint64( #lower, #upper ) ;
Int64=>16進数文字列 (関数) : $hex = hexint64( #lower, #upper ) ;

文字数。
文字数計算      (文) : charcountint64       #mode, #lowerReturn, #upperReturn ; // #modeはcharcount( n1 ) 関数のn1と同じ。
文字位置=>行/桁 (文) : positiontolinecolumn #lowerposition, #upperposition, #lowerlineReturn, #upperlineReturn, #lowercolumnReturn, #uppercolumnReturn ;
行/桁=>文字位置 (文) : linecolumntoposition #lowerline, #upperline, #lowercolumn, #uppercolumn, #lowerpositionReturn, #upperpositionReturn ;

カーソル。
x             (文) : xint64            #lowerReturn, #upperReturn ;
y             (文) : yint64            #lowerReturn, #upperReturn ;
column        (文) : columnint64       #lowerReturn, #upperReturn ;
lineno        (文) : linenoint64       #lowerReturn, #upperReturn ;
tabcolumn     (文) : tabcolumnint64    #lowerReturn, #upperReturn ;
xview         (文) : xviewint64        #lowerReturn, #upperReturn ;
prevposx      (文) : prevposxint64     #lowerReturn, #upperReturn ;
prevposy      (文) : prevposyint64     #lowerReturn, #upperReturn ;
mousecolumn   (文) : mousecolumnint64  #lowerReturn, #upperReturn ;
mouselineno   (文) : mouselinenoint64  #lowerReturn, #upperReturn ;
columntox     (文) : columntoxint64    #lowerc, #upperc, #lowerl, #upperl, #lowerReturn, #upperReturn ;
linenotoy     (文) : linenotoyint64    #lowerc, #upperc, #lowerl, #upperl, #lowerReturn, #upperReturn ;
xtocolumn     (文) : xtocolumnint64    #lowerx, #upperx, #lowery, #uppery, #lowerReturn, #upperReturn ;
ytolineno     (文) : ytolinenoint64    #lowerx, #upperx, #lowery, #uppery, #lowerReturn, #upperReturn ;
up            (文) : upint64           #lower, #upper ;
down          (文) : downint64         #lower, #upper ;
right         (文) : rightint64        #lower, #upper ;
left          (文) : leftint64         #lower, #upper ;
shiftup       (文) : shiftupint64      #lower, #upper ;
shiftdown     (文) : shiftdownint64    #lower, #upper ;
shiftright    (文) : shiftrightint64   #lower, #upper ;
shiftleft     (文) : shiftleftint64    #lower, #upper ;
moveto        (文) : movetoint64       #lowerx, #upperx, #lowery, #uppery ;
movetoview    (文) : movetoviewint64   #lowerx, #upperx, #lowery, #uppery ;
movetolineno  (文) : movetolinenoint64 #lower桁番号, #upper桁番号, #lower行番号, #upper行番号 ;
moveto2       (文) : moveto2int64      #lowercolumn, #uppercolumn, #lowerlineno, #upperlineno ;

テキスト。
linecount  (文)   : linecountint64  #lowerReturn, #upperReturn ;
linecount2 (文)   : linecount2int64 #lowerReturn, #upperReturn ;
linelen    (文)   : linelenint64    #lowerReturn, #upperReturn ;
linelen2   (文)   : linelen2int64   #lowerReturn, #upperReturn ;
gettext    (関数) : $str = gettextint64(  #lowerx1, #upperx1, #lowery1,#uppery1, #lowerx2, #upperx2, #lowery2, #uppery2, #n1 [ , #n2 ] ) ;
gettext2   (関数) : $str = gettext2int64( #lowerc1, #upperc1, #lowerl1,#upperl1, #lowerc2, #upperc2, #lowerl2, #upperl2, #n1 [ , #n2 ] ) ;

範囲選択。
seltopx      (文) : seltopxint64       #lowerReturn, #upperReturn ;
seltopy      (文) : seltopyint64       #lowerReturn, #upperReturn ;
selendx      (文) : selendxint64       #lowerReturn, #upperReturn ;
selendy      (文) : selendyint64       #lowerReturn, #upperReturn ;
seltopcolumn (文) : seltopcolumnint64  #lowerReturn, #upperReturn ;
seltoplineno (文) : seltoplinenoint64  #lowerReturn, #upperReturn ;
selendcolumn (文) : selendcolumnint64  #lowerReturn, #upperReturn ;
selendlineno (文) : selendlinenoint64  #lowerReturn, #upperReturn ;
selopenx     (文) : selopenxint64      #lowerReturn, #upperReturn ;
selopeny     (文) : selopenyint64      #lowerReturn, #upperReturn ;

クリップボード。
selectcolumn (文) : selectcolumnint64 #lower区切り1, #upper区切り1, #lower区切り2, #upper区切り2 [ , #lower行1, #upper行1, #lower行2, #upper行2 ] ;

ウィンドウ。
screentopy  (文) : screentopyint64  #lowerReturn, #upperReturn ;
screenleftx (文) : screenleftxint64 #lowerReturn, #upperReturn ;

検索。
foundtopx           (文) : foundtopxint64           #lowerReturn, #upperReturn ;
foundtopy           (文) : foundtopyint64           #lowerReturn, #upperReturn ;
foundendx           (文) : foundendxint64           #lowerReturn, #upperReturn ;
foundendy           (文) : foundendyint64           #lowerReturn, #upperReturn ;
colormarker         (文) : colormarkerint64         #文字色, #背景色, #スタイル, #種類, #ユーザーデータ, $レイヤー名, #lower開始行, #upper開始行, #lower開始桁, #upper開始桁, #lower終了行, #upper終了行, #lower終了桁, #upper終了桁 ;
deletecolormarker   (文) : deletecolormarkerint64   $レイヤー名, #ユーザーデータ, #lower開始行, #upper開始行, #lower開始桁, #upper開始桁, #lower終了行, #upper終了行, #lower終了桁, #upper終了桁 ;
colormarkerallfound (文) : colormarkerallfoundint64 #文字色, #背景色, #スタイル, #種類, #ユーザーデータ, $レイヤー名, #lower開始行, #upper開始行, #lower開始桁, #upper開始桁, #lower終了行, #upper終了行, #lower終了桁, #upper終了桁 ;
colormarkersnapshot (文) : colormarkersnapshotint64 #lower開始行, #upper開始行, #lower開始桁, #upper開始桁, #lower終了行, #upper終了行, #lower終了桁, #upper終了桁, $レイヤー名 ;

設定。
width     (文) : widthint64     #lowerReturn, #upperReturn ;
formwidth (文) : formwidthint64 #lowerReturn, #upperReturn ;

レジストリ。
writeininum  (文) : writeininumint64  $INIファイル名, $セクション名, $キー名, #lower, #upper ;
writeininumw (文) : writeininumwint64 $INIファイル名, $セクション名, $キー名, #lower, #upper ;
getininum    (文) : getininumint64    $INIファイル名, $セクション名, $キー名, #lowerReturn, #upperReturn ;
getininumw   (文) : getininumwint64   $INIファイル名, $セクション名, $キー名, #lowerReturn, #upperReturn ;
writeregnum  (文) : writeregnumint64  $値の名前, #lower, #upper ;             // REG_QWORD値用。
getregnum    (文) : getregnumint64    $値の名前, #lowerReturn, #upperReturn ; // REG_QWORD値用。

アウトライン。
rangeedittop     (文) : rangeedittopint64     #lowerReturn, #upperReturn ;
rangeeditend     (文) : rangeeditendint64     #lowerReturn, #upperReturn ;
outlineitemcount (文) : outlineitemcountint64 #lowerReturn, #upperReturn ;

マクロ制御。
enabledraw  (文) : enabledrawint64 #lowery, #uppery, #lowerx, #upperx ;

※パラメーターの#lower〜は下位32bit、#upper〜は上位32bit、〜Returnは出力値を受け取る変数。

この例は主に文字数や文字の座標(lineno/columnなど)を64bit化した場合に、既存の文/関数/キーワードと
同等のものを用意したものです。命名は既存のものに末尾にint64を付けています。また、元々1個の数値を
返していた関数/キーワードは一度に#lower〜と#upper〜との2値を返さないといけないため、getlinecount()の
nReturnと同様な参照渡しパラメーターで値を受け取る文として再定義しました。

これはあくまで当方で思いついた一例ですので、もっとスマートな方法があるかもしれません。

[ ]
RE:10437 [不具合]文字数カウントNo.10440
fzok4234 さん 21/05/26 23:28 [ コメントを投稿する ]
  > setfloatmode 1;のときで動作を変えるべきかというのは微妙で、全部合わせたほうがいい気も
> しますが、とりあえずそもそも可能かどうか試してみて検討します

とりあえず、当面は浮動小数点数モードを「32bitの壁」を突破する手段として利用できるように
整備を進めることが賢明な解決法かもしれません。

[ ]
RE:10440 [不具合]文字数カウントNo.10441
こみやんま さん 21/05/26 23:59 [ コメントを投稿する ]
  自分はめったに反対意見は言わないんですが、
さすがに、32bitのマクロ空間に64bit整数用命令や仕組みを大量投入というのは反対です。

多くのスクリプト言語も32bit版はnumberは32bitですし、
ほぼ全てのメソッドもその「32bit版なら32bitの範囲でやりとりされる」よう実装されています。
64bit版秀丸もあるので、64bit変数が必要な人は64bit使え
という感じの切り分けでいいかと思います。

(まぁトップクラスの流行のpythonがデフォルトの整数型が「無限桁数」で32bitも64bitも数値範囲かわらんし無限というすごい状態ですがw)

ただ、**64bit版秀丸なのに**、「この変数64bitまで行く可能性がそこそこあるのに32bitでのやりとり」になってるよね? とかいう箇所があるのであれば、
そこはピンポイントで「64bit版では、64bit整数」を返した方がいいんじゃないですか、ぐらいですね。
[ ]
RE:10441 [不具合]文字数カウントNo.10442
fzok4234 さん 21/05/27 03:48 [ コメントを投稿する ]
  > 自分はめったに反対意見は言わないんですが、
> さすがに、「32bitのマクロ空間」に64bit整数用命令や仕組みを大量投入というのは反対です。

> 多くのスクリプト言語も「32bit版」はnumberは32bitですし、
> ほぼ全てのメソッドもその「32bit版なら32bitの範囲でやりとりされる」よう実装されています。
> 「64bit版秀丸」もあるので、64bit変数が必要な人は64bit使え
> という感じの切り分けでいいかと思います。

> ただ、**64bit版秀丸なのに**、「この変数64bitまで行く可能性がそこそこあるのに32bitでのやりとり」に
> なってるよね? とかいう箇所があるのであれば、
> そこはピンポイントで「64bit版では、64bit整数」を返した方がいいんじゃないですか、ぐらいですね。

問題の本質はまさにこの「64bit版秀丸エディタなのに32bitの壁に阻まれている。」ということであります。

初めから「32bit版秀丸エディタ」を使っていて文字数などのオーバーフローに直面するのは「当然のこと」であり、
この狭いマクロ空間で「64bit整数用命令や仕組み」を求めるのは「水の中に火を、火の中に水を」求めるが如く
ナンセンスなことであります。まさに、
・さすがに、「32bitのマクロ空間」に64bit整数用命令や仕組みを大量投入というのは反対です。
・ほぼ全てのメソッドもその「32bit版なら32bitの範囲でやりとりされる」よう実装されています。
という感じです。

しかし、今度の舞台はまさしく「64bit版秀丸エディタ」であり、この「広いはずのマクロ空間」で64bit整数用命令や
仕組みの大量投入を求めていくことは間違っているとは言えません。だが残念なことに、この「一見広く見えるマクロ空間」の
実態は昔の32bit全盛期に作られた「狭い32bitのマクロ空間」をそのまま移植したものであったわけです。その理由は、
・ソースレベルで32bitの変数やメソッドの実装を全て64bit化するには多大なコストがかかること。
・下位互換性を維持して既存のマクロやDLLの正常動作を保証するため。
であり、決して悪いことではありません。

でもやはり、OSやファイルシステムの64bit版が主流となり、これに合わせて扱うコンテンツも大容量化してきた
今日においては、この「狭い32bitのマクロ空間」は時代遅れの過去の遺物となっていて、真の意味で広いマクロ空間へと
「リフォーム」すべき時が来ているのではないかと思います。では、この「リフォーム」はどのように行われるべきかと
いえば、それは
・1つのマクロ空間上に32bit用命令/仕組みと64bit用命令/仕組みとが同居可能にする。
ことに尽きるはずです。つまり、
・従来の32bit用命令/仕組みを温存したまま新たに64bit用命令/仕組みを追加する。
ということになります。もちろんこれは、素質として64bitの広さを持った「64bit版秀丸エディタ」限定であり、
これ以上広くできない「32bit版秀丸エディタ」は対象外です。

ここで1つ問題があります。それは、マクロの変数の型は「数値」と「文字列」の2種類しかないことです。この2種類だけで
従来の「32bit整数」、「倍精度浮動小数点数(Float版秀丸エディタのみ)」、「Unicode文字列」に加えて新たに
「64bit整数」を表現しないといけません。そのための方法として思いつくいくつかの案には次のようなものがあります。
1.「数値」は単独で32bit整数のままだが、これを2個で1組として64bit整数を表現する。この2個1組の数値をやり取り
  する文/関数を追加して実装する。先ほど具体例を挙げたやり方。
2.setfloatmode文を使って「数値」の内部形式自体を切り替える。従来は
  setfloatmode 0; で32bit整数となり、
  setfloatmode 1; で倍精度浮動小数点数となっていたが、これに加えて
  setfloatmode 2; で64bit整数する「64bitモード」を新設する。まさに
  ・そこはピンポイントで「64bit版では、64bit整数」を返した方がいいんじゃないですか。
  という感じである。
3.「文字列」に@"0x0F1E2D3C4B5A6978"といった桁数固定の16進数文字列を格納して64bit整数を表現する。この16進数値を
  やり取りする文/関数を追加して実装する。
4.メモリ上に置かれた64bit整数オブジェクトの実体を識別する「ハンドル値」を32bit整数の「数値」で取り扱う。
  loaddll()でロードしたDLLやcreateobject()で作成したCOMオブジェクト、hidemaruhandle()で取得するウィンドウなどと
  同じノリで専らハンドルを介して64bit整数オブジェクトを操作する。このハンドルをやり取りする文/関数を追加して実装する。
いずれも、現行の64bit版秀丸エディタとの下位互換性を考慮してのことです。

[ ]
RE:10442 [不具合]文字数カウントNo.10443
でるもんたいいじま さん 21/05/27 06:08 [ コメントを投稿する ]
  でるもんた・いいじまです。

> 問題の本質はまさにこの「64bit版秀丸エディタなのに32bitの壁に
> 阻まれている。」ということであります。

まあ、それはわかります。

ただ、fzok4234さん以外の他にだれも「秀丸を大々的に現代化すべきだ」という意見が出ないのは、ハッキリ言ってしまえばfzok4234さんが「秀丸にそれを求めるということがもともと無茶な案件を次から次へと、しかも大上段の態度で要求し続けているから」だと考えます。

それだけの膨大な開発資金なんて、はっきり言ってしまえばサイトー企画さんが調達するつもりはないでしょう。それに、仮にその資金で人員を確保して作業したとしても、品質の劣化と既存客離れを招くだけ、と私は見込んでいます。

(秀まるおさん・担当さんレベルの優秀なエンジニアって、日本中どこを探してもなかなか見つからないですよ。私ならそのクラスの人材をフルタイムで雇えるなら年俸1億でも激安だと考えます。)

そもそも秀丸はたった15MBの小型アプリ、開発元も資本金300万円の零細企業(スタッフ数もひと桁のはずです)です。そこに対して「資本金200億円・スタッフ数4桁(もしかしたら5桁以上?)の巨大企業とタイマン張ってガチンコ勝負しろ」と吹っ掛けている、この無謀な要求こそがfzok4234さんの今までの一貫した無茶振りの正体です。

> でもやはり、OSやファイルシステムの64bit版が主流となり、
> これに合わせて扱うコンテンツも大容量化してきた今日においては、

うーむ。今は64bit環境といえどもまだ、GB単位のデータをユーザが可変長データストリーム用のテキストエディタで簡単に編集できる時代だとは思いませんけどね。
たとえば、長大なJSONデータに細かいパッチを当てたい、みたいなケースでテキストエディタを迂闊に使うと文法エラーを起こしかねませんから、そういうものは専用の編集ツールが筋です。

まあ私でも、自作のスクリプト上でなら100MBくらいのテキストデータは平気で扱うことがありますけど。

> ・従来の32bit用命令/仕組みを温存したまま新たに64bit用命令/仕組みを追加する。
> ということになります。もちろんこれは、素質として64bitの広さを持った
> 「64bit版秀丸エディタ」限定であり、
> これ以上広くできない「32bit版秀丸エディタ」は対象外です。

32bit版の秀丸エディタでメモリ空間をこれ以上広げられない件と、現状で64bit整数演算ができない件とは全く無関係ですが?64bit整数演算を実装するだけなら32bitの秀丸にも十分に導入可能です。

> 1.「数値」は単独で32bit整数のままだが、これを2個で1組として
> 64bit整数を表現する。この2個1組の数値をやり取りする文/関数を
> 追加して実装する。先ほど具体例を挙げたやり方。

これは絶対に反対です。可読性が著しく落ちます。
無限倍長整数四則演算のコードを、C++ではなくフルアセンブラで再発明しようと挑戦してみればそのしんどさが分かるはずです。

そもそも、たとえばZ80の時代には、環境によっては単純な「8bit×8bit→16bit」の掛け算すらアセンブラで書かなきゃいけなかったんですよ?その時代の苦労が想像できますか?
(時代が下るとZ80でもC言語が普及してきて、そういう基本的な計算はランタイムライブラリを呼ぶだけで済むようになりましたけどね。)

> 2.setfloatmode文を使って「数値」の内部形式自体を切り替える。従来は
>   setfloatmode 0; で32bit整数となり、
>   setfloatmode 1; で倍精度浮動小数点数となっていたが、これに加えて
>   setfloatmode 2; で64bit整数する「64bitモード」を新設する。

これは確かに検討に値すると思います。
でもそうすると、いま整数版と浮動小数点版に分かれているパッケージを後者のみに統一する、ということになりますね。実現性をしっかり検討してみたいとこです。

> 3.「文字列」に@"0x0F1E2D3C4B5A6978"といった桁数固定の16進数文字列を
> 格納して64bit整数を表現する。この16進数値をやり取りする文/関数を
> 追加して実装する。

これは反対。「+」演算子が期待通りに働きません。

☆ ☆ ☆

もうひとつ、私からも別の提案です。

「64bit整数型の変数には、既存の #、$ とは別のprefixをつけて区別する。」
ASCII文字の中て、1文字で新規のプレフィックスとして使えそうな記号は @ ` _ くらいしかありませんが、C言語の L'あ' や L"abc" あたりからの類推で L#abc、Q#abc あたりを検討してみてもいいと思います。あと、#_abc は現状、有効な変数名なんでしたっけ?

いかがでしょう。
[ ]
RE:10442 [不具合]文字数カウントNo.10444
こみやんま さん 21/05/27 09:13 [ コメントを投稿する ]
  現在の秀丸エディタ64bit版のマクロ変数や関数の整数精度はすでに64bit幅ですよね?

何を解決しようとしているのかよくわからない...


現在の秀丸エディタ64bit版の整数精度が32bitであるかのような提案がなされているように思えます。
[ ]
RE:10443 [不具合]文字数カウントNo.10445
秀丸担当 さん 21/05/27 09:17 [ コメントを投稿する ]
 
64bitでも扱えるようにできたらいいということで、各種の文や関数を大量に作るというのは大変そうです。
setfloatmode 2;
でできたら、いろいろ合理的でいいかもしれないです。
どんな困難があるかやってみないとわかないこともあると思いますが、うまくいけば32bit版floatでも64bit整数を扱えるように統一できるようになるかもしれません。
V9のネタにするか、作ったとしてもそんなに使う人はいない気もするので、最近はよくあるパターンで正式版でも特定機能はベータとかExperimentとかいう扱いで置いておくのでもいいかもしれないです。
[ ]
RE:10444 [不具合]文字数カウントNo.10446
秀丸担当 さん 21/05/27 09:51 [ コメントを投稿する ]
 
これはヘルプにちゃんと書いていないのがいけないのですが、64bit版の浮動小数点数版では、setfloatmode 0;の状態で32bitの整数の扱いになってしまうということがあります。
そのあたりもヘルプに書いておきます。
いろいろ歴史的経緯と内部事情があるのですが、もともと32bit通常版と浮動小数点数版は、int(32bit)とdouble(仮数部52bit)になっていて、setfloatmode 0;ではdoubleをintに変換していました。
一方で64bit版ができて、64bit通常版は64bit格納できても、64bit浮動小数点数版はやっぱりdouble(仮数部52bit)なので、64bit整数は扱えないです。
そのため、setfloatmode 0;の状態で通常版と同じになる、というのは、浮動小数点数版においては32bitになってしまいます。
それで、setfloatmode 2;でとにかく64bit整数にできたら全部統一できて合理的になる可能性があります。
[ ]
RE:10446 [不具合]文字数カウントNo.10447
こみやんま さん 21/05/27 10:00 [ コメントを投稿する ]
  ああ、
64bit整数版は問題なく64bitで動作するものの、
64bit版の浮動小数版の精度がdoubleのまま、intが32bitで精度が足りてないんですね。

それはおっしゃるように、モードを追加し、
64bit整数モード(浮動小数あきらめる)で、64bit(ノーマル版)相当の動きにすればよいかと思います。
[ ]
RE:10443 [不具合]文字数カウントNo.10450
fzok4234 さん 21/05/27 13:35 [ コメントを投稿する ]
  > ただ、fzok4234さん以外の他にだれも「秀丸を大々的に現代化すべきだ」という意見が出ないのは、
> ハッキリ言ってしまえばfzok4234さんが「秀丸にそれを求めるということがもともと無茶な案件を
> 次から次へと、しかも大上段の態度で要求し続けているから」だと考えます。

> それだけの膨大な開発資金なんて、はっきり言ってしまえばサイトー企画さんが調達するつもりは
> ないでしょう。それに、仮にその資金で人員を確保して作業したとしても、品質の劣化と既存客離れを
> 招くだけ、と私は見込んでいます。

> (秀まるおさん・担当さんレベルの優秀なエンジニアって、日本中どこを探してもなかなか見つからないですよ。
> 私ならそのクラスの人材をフルタイムで雇えるなら年俸1億でも激安だと考えます。)

> そもそも秀丸はたった15MBの小型アプリ、開発元も資本金300万円の零細企業(スタッフ数もひと桁の
> はずです)です。そこに対して「資本金200億円・スタッフ数4桁(もしかしたら5桁以上?)の巨大企業と
> タイマン張ってガチンコ勝負しろ」と吹っ掛けている、この無謀な要求こそがfzok4234さんの今までの
> 一貫した無茶振りの正体です。

確かに、
・VS Code
を開発する天下のMicrosoftと対峙することは「戦車に竹槍で応戦」するが如く「無謀」なことだと思います。
しかし、これが
・サクラエディタ
・Notepad++
・Mery
などの個人や零細コミュニティが開発するものとなれば、比較的「同じ土俵」で対峙しているといえます。
これらの零細エディタ陣営側の機能紹介を見ていると、
・オープンソースかつ無料。
・Unicode化や64bit化のために1から書き直す。
・古いOSのサポートをバッサリ切る。
などのなかなか強かな戦法を取ってきたりしています。油断していると、先にLanguage Server Protocolなど
を実装されるなどの遅れをとる恐れもあります。

> 32bit版の秀丸エディタでメモリ空間をこれ以上広げられない件と、現状で64bit整数演算ができない件とは
> 全く無関係ですが?64bit整数演算を実装するだけなら32bitの秀丸にも十分に導入可能です。

基本的に秀丸エディタはWindows APIを直に叩くアンマネージドC/C++で書かれている以上、32bit版秀丸エディタで
64bitの整数演算やAPIに対応することは複雑なトリックを使用するためにかなりの大改修となり、それこそ
「開発元も資本金300万円の零細企業(スタッフ数もひと桁のはずです)に対する無謀な要求」になってしまいそうです。
逆に、64bit版秀丸エディタで64bitの整数演算やAPIに対応することはそれほど大きなコストはかからないと
思われます。

> もうひとつ、私からも別の提案です。

> 「64bit整数型の変数には、既存の #、$ とは別のprefixをつけて区別する。」
> ASCII文字の中て、1文字で新規のプレフィックスとして使えそうな記号は @ ` _ くらいしかありませんが、C言語の L'あ' や L"abc" あたりからの類推で L#abc、Q#abc あたりを検討してみてもいいと思います。あと、#_abc は現状、有効な変数名なんでしたっけ?

> いかがでしょう。

やはり、最終的にはこのような「マクロの文法自体の改修」が理想的かと思われます。

[ ]
RE:10450 [不具合]文字数カウントNo.10451
こみやんま さん 21/05/27 13:51 [ コメントを投稿する ]
  Language Server Protocol というのは、ローカルで利用できる言語サーバーとして共有されているものを、比較的簡素なプログラムで利用できるものになっています。

例えば、いつ頃だったか軽くつくってみたものでは、
https://xn--pckzexbx21r8q9b.net/?page=nobu_tool_hm_ts_intellisense

が秀丸でLanguage Server Protocol を利用しているもので、
JavaScriptがリアルタイムにTypeScript級の型分析がなされています。


利用する側(サイトー企画も利用する側になりますね)実装自体は比較的簡単ですが、いままで外部API
(Web APIもそうだし、この場合ローカルのnodeに依存することにもなる)に依存はできるだけ回避する方針で開発されている様子がありますので、
この辺をサイトー企画さん側で実装するのは難しいかなぁと思っています。

マンパワー的にも、Language Protocol Serverを使ったモジュールを秀丸上で実装するのに欠けているAPIを秀丸から提供し、
それを利用してエディタ取り巻きがモジュールを作り上げるのが良いのですが、
v8.66だったかv8.73あたりでその辺を結構強く希望したのですが、
入力補完候補への(マクロを経由しない)割り込みを認められませんでした。
(これらが認められないと安心して配布できるモジュールとしては作りがたいです)

(強引に「そのレベルで割り込む?」というプログラムをかけば
 https://xn--pckzexbx21r8q9b.net/?page=nobu_tool_hm_autocompleteex
 みたいに入力補完にいきなり割り込むことはできますが、
 まぁ正道ではないよねっていう...)
[ ]
RE:10445 [不具合]文字数カウントNo.10452
fzok4234 さん 21/05/27 14:54 [ コメントを投稿する ]
  整数のオーバーフローについて調べてみると、
JPCERT : https://www.jpcert.or.jp/sc-rules/c-int32-c.html
IPA    : https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c907.html
といった公的機関により「セキュリティ上の脆弱性」とみなされているようで、これを放置することは
あまり良くないことという印象を受けました。

今回は「文字数ダイアログ」という比較的深刻度の小さいことで問題が顕在化しましたが、これ以外にも
ユーザーの目に見えない部分で存在しているかもしれません。特に文字数や文字インデックス番号、
行/桁に依存する部分で今後問題が生ずる可能性も考えられます。最悪、
・巨大ファイルを悪用して任意の悪意あるコードを実行する。
ような輩が出没するかもしれません。

それからマクロ上でのことですが、試しに

debuginfo 2 ;
debuginfo @"[0x7FFFFFFE + 1]" + "\U0000000A" ;
#number = 0x7FFFFFFE + 1 ;
#result = result ;
debuginfo @"Number=" + str( #number ) + "\U0000000A" ;
debuginfo @"Result=" + str( #result ) + "\U0000000A" ;
debuginfo @"[0x7FFFFFFF + 1]" + "\U0000000A" ;
#number = 0x7FFFFFFF + 1 ;
#result = result ;
debuginfo @"Number=" + str( #number ) + "\U0000000A" ;
debuginfo @"Result=" + str( #result ) + "\U0000000A" ;
endmacro ;

を実行すると、結果は

[0x7FFFFFFE + 1]
Number=2147483647
Result=0
[0x7FFFFFFF + 1]
Number=-2147483648
Result=0

となってresultキーワードでは整数オーバーフローを捕捉できないことがわかりました。

このことから提案があるのですが、マクロ開発者が各自で整数オーバーフロー対策を行いやすいように
自動でチェックを行う動作モードを新設する、というのはどうでしょうか。すなわち、
setoverflowcheckmode文
なるものを用意して、整数オーバーフローが起きたらエラーとして捕捉できるようにするモードを
有効にできるようにすることです。例えば、
setoverflowcheckmode 0 ; // 従来の動作と同じで何もチェックしない。
setoverflowcheckmode 1 ; // getresultex()関数で捕捉する。
setoverflowcheckmode 2 ; // 実行時エラーとして直ちに処理を停止する。
という感じです。

[ ]
RE:10452 [不具合]文字数カウントNo.10453
でるもんたいいじま さん 21/05/27 15:40 [ コメントを投稿する ]
  でるもんた・いいじまです。

> 整数のオーバーフローについて調べてみると、
> JPCERT : https://www.jpcert.or.jp/sc-rules/c-int32-c.html
> IPA    : https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c907.html
> といった公的機関により「セキュリティ上の脆弱性」とみなされているようで、
> これを放置することは
> あまり良くないことという印象を受けました。

リンク先を読んでいない(し、まず間違いなくfzok4234さんの曲解なのでわざわざ読む必要も感じない)のですが、「どんな場合でも」32bit(あるいは64bit)の境界を溢れる整数演算は悪である、という主張には強く異議を申し述べておきます。

そもそも、Pythonならともかくアセンブラあたりだと、桁溢れを意図的に起こさないことには整数演算のロジック自体が成立しません。

> resultキーワードでは整数オーバーフローを捕捉できないことがわかりました。

当然です。

> このことから提案があるのですが、マクロ開発者が各自で整数オーバーフロー
> 対策を行いやすいように自動でチェックを行う動作モードを新設する、
> というのはどうでしょうか。すなわち、
> setoverflowcheckmode文
> なるものを用意して、

そうすると「 & 0x80000000」みたいなビット演算を文法レベルで禁止しないと意味がないですね。x86/x64アーキテクチャ的にも面倒ですし、効率的に実装しようとすればC言語の中に大量のインラインアセンブラが混入することにもなりかねないので、反対します。

☆ ☆ ☆

繰り返します。
「ご自身も含めて誰も使わないもの」を大量でタダで作れという要求はそろそろやめてください。
それにあなたは秀丸のセールス&マーケティング責任者でも何でもありません。勝手に「俺が現代人の総意だ」という口ぶりで出しゃばらないでください。
[ ]
RE:10453 [不具合]文字数カウントNo.10454
fzok4234 さん 21/05/27 16:12 [ コメントを投稿する ]
  > 「ご自身も含めて誰も使わないもの」を大量でタダで作れという**要求**は
> そろそろやめてください。
> それにあなたは秀丸のセールス&マーケティング責任者でも何でもありません。
> 勝手に「俺が現代人の総意だ」という口ぶりで出しゃばらないでください。

実装を強く求める「要求」ではなく、こういうアイデアがあることを示しただけの
「提案」です。実装に多大なコストがかかるようであれば無理に実装する必要の
ないもので、「もしゆとりがあれば将来こういうものを検討してみてはいかが?」と
いう程度のものです。

くれぐれも誤解なきようお願いします。

[ ]
RE:10453 [不具合]文字数カウントNo.10456
fzok4234 さん 21/05/27 16:43 [ コメントを投稿する ]
  それから、文字数や行/桁のように大きくなりがちな整数値の計算には、知らず知らずの
うちにオーバーフローさせてしまうリスクを伴います。これを回避するためには、
先ほど紹介したJPCERTのサイトで紹介されているような2項演算子に対応する
サブルーチンを前もって用意しておく必要があります。

しかしながら、秀丸マクロのサブルーチンの仕様は、戻り値を一旦変数##returnに
保存する方式のため、例えば
#val = ( #a + #b ) / #c + ( #d - #e ) * / #f ;
という風に1つの式中に2項演算が複雑に入り組んでいる場合では、安全な
サブルーチンに置き換えると記述量が大幅に増えて可読性や保守性も著しく
損なわれてしまいます。

もしでるもんた・いいじまさんが現在の秀丸マクロの仕様だけで実現可能な
もっとスマートな記述方法を御存知であるならば、それを紹介すればよいだけの
話ではないでしょうか。

[ ]
RE:10456 [不具合]文字数カウントNo.10460
秀丸担当 さん 21/05/28 13:00 [ コメントを投稿する ]
 
C++等のネイティブコードは脆弱性になりうると思いますが、マクロの実行空間のこととはまた別という気がします。
何らかの問題の要因にはなるかもしれないので、可能性はゼロとは言い切れないですが。
オーバーフローしたかどうかを簡単にチェックできたらいいと思います。いつでもgetresultex(n)とかで知れれば、簡便かもしれません。
四則演算などだけでなく、あらゆるケースにおいて漏れなくチェックするようにできるかというとわからないです。
ゆとりがあれば将来そういうものを検討できたらいいと思います。
[ ]
RE:10460 [不具合]文字数カウントNo.10462
fzok4234 さん 21/05/28 13:12 [ コメントを投稿する ]
  ご検討の方ありがとうございます。

とりあえず、当方においては代替の四則演算用のサブルーチン(あるいは外部DLLのメソッド)を
作って、ファイル全体の文字数や行/桁の番号の演算に使用して当座はしのごうかと
思ってます。

[ ]
RE:10460 [不具合]文字数カウントNo.10467
fzok4234 さん 21/05/31 13:57 [ コメントを投稿する ]
  v8.98β10 Float x64にて、2500000000文字のファイルに対して「文字数」ダイアログが
正しく機能することと、charcount()関数が0を返すことを確認しました。
また、
( -2147483648 ) / ( -1 )
( -2147483648 ) % ( -1 )
- ( -2147483648 )
の演算でオーバーフローエラーとなることも確認できました。

修正ありがとうございます。

[ ]

[ 新規に投稿する ]